@ramathibodi/nuxt-commons 0.1.59 → 0.1.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/runtime/components/ImportCSV.vue +2 -1
- package/dist/runtime/components/form/ActionPad.vue +1 -0
- package/dist/runtime/components/form/Date.vue +11 -2
- package/dist/runtime/components/form/Dialog.vue +1 -0
- package/dist/runtime/components/form/EditPad.vue +1 -0
- package/dist/runtime/components/form/Pad.vue +42 -14
- package/dist/runtime/components/model/Pad.vue +19 -1
- package/dist/runtime/components/model/Table.vue +22 -4
- package/dist/runtime/composables/document/template.js +1 -1
- package/dist/runtime/composables/utils/validation.d.ts +20 -0
- package/dist/runtime/composables/utils/validation.js +11 -1
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -102,7 +102,8 @@ const assignNestedValue = (obj: any, keys: string[], value: any) => {
|
|
|
102
102
|
const parseIfJson = (value: any) => {
|
|
103
103
|
if (typeof value === 'string') {
|
|
104
104
|
try {
|
|
105
|
-
|
|
105
|
+
let parsedValue = JSON.parse(value)
|
|
106
|
+
return (parsedValue==value) ? value : parsedValue
|
|
106
107
|
} catch {
|
|
107
108
|
// If parsing fails, return the original value
|
|
108
109
|
return value
|
|
@@ -3,9 +3,10 @@ import { ref, watch, watchEffect, nextTick, defineExpose, computed} from 'vue'
|
|
|
3
3
|
import { VTextField } from 'vuetify/components/VTextField'
|
|
4
4
|
import Datepicker from '@vuepic/vue-datepicker'
|
|
5
5
|
import '@vuepic/vue-datepicker/dist/main.css'
|
|
6
|
-
import {isArray, isString} from "lodash-es";
|
|
6
|
+
import { isArray, isString } from "lodash-es";
|
|
7
7
|
import { type dateFormat, Datetime } from '../../utils/datetime'
|
|
8
8
|
import { useRules } from "../../composables/utils/validation";
|
|
9
|
+
import { th } from 'date-fns/locale';
|
|
9
10
|
|
|
10
11
|
interface Props extends /* @vue-ignore */ InstanceType<typeof VTextField['$props']> {
|
|
11
12
|
locale?: 'TH' | 'EN'
|
|
@@ -244,7 +245,15 @@ defineExpose({
|
|
|
244
245
|
auto-apply
|
|
245
246
|
inline
|
|
246
247
|
:locale="locale"
|
|
248
|
+
:format-locale="(locale=='TH') ? th : undefined"
|
|
247
249
|
@update:model-value="updateDatePicker"
|
|
248
|
-
|
|
250
|
+
>
|
|
251
|
+
<template #year="{value}" v-if="locale=='TH'">
|
|
252
|
+
{{value+543}}
|
|
253
|
+
</template>
|
|
254
|
+
<template #year-overlay-value="{value}" v-if="locale=='TH'">
|
|
255
|
+
{{value+543}}
|
|
256
|
+
</template>
|
|
257
|
+
</Datepicker>
|
|
249
258
|
</v-menu>
|
|
250
259
|
</template>
|
|
@@ -16,7 +16,7 @@ import {isObject} from 'lodash-es'
|
|
|
16
16
|
import {watchDebounced} from '@vueuse/core'
|
|
17
17
|
import {useRules} from '../../composables/utils/validation'
|
|
18
18
|
import {useDocumentTemplate} from '../../composables/document/template'
|
|
19
|
-
import { isArray, isString, isPlainObject } from 'lodash-es'
|
|
19
|
+
import { isArray, isString, isPlainObject, isEqual } from 'lodash-es'
|
|
20
20
|
import FormPad from './Pad.vue'
|
|
21
21
|
|
|
22
22
|
defineOptions({
|
|
@@ -25,6 +25,7 @@ defineOptions({
|
|
|
25
25
|
|
|
26
26
|
interface Props {
|
|
27
27
|
modelValue?: object
|
|
28
|
+
originalData?: object
|
|
28
29
|
template?: any
|
|
29
30
|
templateScript?: string
|
|
30
31
|
disabled?: boolean
|
|
@@ -32,6 +33,8 @@ interface Props {
|
|
|
32
33
|
isolated?: boolean
|
|
33
34
|
decoration?: object
|
|
34
35
|
parentTemplates?: string|string[]
|
|
36
|
+
dirtyClass?: string
|
|
37
|
+
dirtyOnCreate?: boolean
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -40,6 +43,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
40
43
|
isolated: false,
|
|
41
44
|
decoration: () => { return {} },
|
|
42
45
|
parentTemplates: (): string[] => [],
|
|
46
|
+
dirtyClass: "form-data-dirty",
|
|
47
|
+
dirtyOnCreate: false
|
|
43
48
|
})
|
|
44
49
|
|
|
45
50
|
const emit = defineEmits(['update:modelValue'])
|
|
@@ -83,36 +88,35 @@ function isBlankString(v: unknown): v is string {
|
|
|
83
88
|
return isString(v) && v.length === 0
|
|
84
89
|
}
|
|
85
90
|
|
|
86
|
-
function sanitizeBlankStrings(val: any):
|
|
87
|
-
|
|
91
|
+
function sanitizeBlankStrings(val: any, original?: any): void {
|
|
92
|
+
if (!original && props.originalData) {
|
|
93
|
+
sanitizeBlankStrings(val, props.originalData)
|
|
94
|
+
return
|
|
95
|
+
}
|
|
88
96
|
|
|
89
97
|
if (isArray(val)) {
|
|
90
98
|
for (let i = val.length - 1; i >= 0; i--) {
|
|
91
99
|
const item = val[i]
|
|
92
100
|
if (isBlankString(item)) {
|
|
93
|
-
val.splice(i, 1)
|
|
94
|
-
changed = true
|
|
101
|
+
val.splice(i, 1)
|
|
95
102
|
} else if (isPlainObject(item) || isArray(item)) {
|
|
96
|
-
|
|
103
|
+
sanitizeBlankStrings(item,{})
|
|
97
104
|
}
|
|
98
105
|
}
|
|
99
|
-
return
|
|
106
|
+
return
|
|
100
107
|
}
|
|
101
108
|
|
|
102
109
|
if (isPlainObject(val)) {
|
|
103
110
|
for (const key of Object.keys(val)) {
|
|
104
111
|
const v = val[key]
|
|
105
112
|
if (isBlankString(v)) {
|
|
106
|
-
delete val[key]
|
|
107
|
-
changed = true
|
|
113
|
+
if (original && !Object.keys(original).includes(key)) delete val[key]
|
|
108
114
|
} else if (isPlainObject(v) || isArray(v)) {
|
|
109
|
-
|
|
115
|
+
let originalChild = (original && (isPlainObject(original[key]) || isArray(original[key]))) ? original[key] : {}
|
|
116
|
+
sanitizeBlankStrings(v, originalChild)
|
|
110
117
|
}
|
|
111
118
|
}
|
|
112
|
-
return changed
|
|
113
119
|
}
|
|
114
|
-
|
|
115
|
-
return false
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
watch(formData, (newValue) => {
|
|
@@ -124,6 +128,23 @@ watch(() => props.modelValue, (newValue) => {
|
|
|
124
128
|
formData.value = isObject(newValue) ? newValue : {}
|
|
125
129
|
}, { deep: true, immediate: true })
|
|
126
130
|
|
|
131
|
+
const injectedClass = computed<Record<string, string>>(() => {
|
|
132
|
+
const data = (formData.value ?? {}) as Record<string, any>
|
|
133
|
+
const result: Record<string, string> = {}
|
|
134
|
+
|
|
135
|
+
if (!props.dirtyOnCreate && !props.originalData) return result
|
|
136
|
+
|
|
137
|
+
const original = (props.originalData ?? {}) as Record<string, any>
|
|
138
|
+
|
|
139
|
+
for (const key of Object.keys(data)) {
|
|
140
|
+
if (!isEqual(data[key], original[key])) {
|
|
141
|
+
if (!data[key] && !original[key]) continue
|
|
142
|
+
result[key] = props.dirtyClass || 'form-data-dirty'
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return result
|
|
146
|
+
})
|
|
147
|
+
|
|
127
148
|
const formComponent = shallowRef()
|
|
128
149
|
|
|
129
150
|
function buildFormComponent() {
|
|
@@ -131,12 +152,13 @@ function buildFormComponent() {
|
|
|
131
152
|
const originalConsoleError = console.warn
|
|
132
153
|
console.warn = (error: any) => { throw new Error(error) } // eslint-disable-line
|
|
133
154
|
try {
|
|
134
|
-
const componentTemplate = '<form-pad ref="formPadTemplate" v-model="formComponentData" :disabled="disabled" :readonly="readonly" :decoration="decoration" :isolated="isolated"><template v-slot="{ data,isDisabled,isReadonly,rules,formProvided,decoration }">' + trimmedTemplate.value + '</template></form-pad>'
|
|
155
|
+
const componentTemplate = '<form-pad ref="formPadTemplate" v-model="formComponentData" :originalData="originalData" :disabled="disabled" :readonly="readonly" :decoration="decoration" :isolated="isolated"><template v-slot="{ data,isDisabled,isReadonly,rules,formProvided,decoration,injectedClass }">' + trimmedTemplate.value + '</template></form-pad>'
|
|
135
156
|
compile(componentTemplate)
|
|
136
157
|
formComponent.value = defineComponent({
|
|
137
158
|
components: { FormPad },
|
|
138
159
|
props: {
|
|
139
160
|
modelValue: { type: Object, default: undefined },
|
|
161
|
+
originalData: { type: Object, default: undefined },
|
|
140
162
|
disabled: { type: Boolean, default: false },
|
|
141
163
|
readonly: { type: Boolean, default: false },
|
|
142
164
|
decoration: { type: Object, default: () => { return {} } },
|
|
@@ -231,6 +253,7 @@ defineExpose({
|
|
|
231
253
|
:is-readonly="readonly"
|
|
232
254
|
:rules="rules"
|
|
233
255
|
:decoration="decoration"
|
|
256
|
+
:injectedClass="injectedClass"
|
|
234
257
|
/>
|
|
235
258
|
</template>
|
|
236
259
|
</v-form>
|
|
@@ -242,6 +265,7 @@ defineExpose({
|
|
|
242
265
|
:is-readonly="readonly"
|
|
243
266
|
:rules="rules"
|
|
244
267
|
:decoration="decoration"
|
|
268
|
+
:injectedClass="injectedClass"
|
|
245
269
|
/>
|
|
246
270
|
</template>
|
|
247
271
|
<component
|
|
@@ -249,6 +273,7 @@ defineExpose({
|
|
|
249
273
|
v-if="trimmedTemplate"
|
|
250
274
|
ref="formPad"
|
|
251
275
|
v-model="formData"
|
|
276
|
+
:originalData="originalData"
|
|
252
277
|
:disabled="disabled"
|
|
253
278
|
:readonly="readonly"
|
|
254
279
|
:decoration="decoration"
|
|
@@ -256,3 +281,6 @@ defineExpose({
|
|
|
256
281
|
:class="$attrs.class"
|
|
257
282
|
/>
|
|
258
283
|
</template>
|
|
284
|
+
<style>
|
|
285
|
+
.form-data-dirty,.form-data-dirty *{color:color-mix(in srgb,currentColor 70%,rgb(var(--v-theme-primary)))!important;text-shadow:0 0 .02em currentColor}
|
|
286
|
+
</style>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { computed, useTemplateRef, defineExpose } from 'vue'
|
|
3
3
|
import { type GraphqlModelItemProps, useGraphqlModelItem } from '../../composables/graphqlModelItem'
|
|
4
|
+
import type {FormDialogCallback} from '../../types/formDialog'
|
|
4
5
|
import EditPad from '../form/EditPad.vue'
|
|
6
|
+
import {useDialog} from "../../composables/dialog";
|
|
5
7
|
|
|
6
8
|
defineOptions({
|
|
7
9
|
inheritAttrs: false,
|
|
@@ -14,6 +16,8 @@ const props = withDefaults(defineProps<Props & GraphqlModelItemProps>(), {
|
|
|
14
16
|
fields: () => ['*'],
|
|
15
17
|
})
|
|
16
18
|
|
|
19
|
+
const emit = defineEmits(['create', 'update'])
|
|
20
|
+
|
|
17
21
|
const { item,
|
|
18
22
|
canCreate, canUpdate,
|
|
19
23
|
createItem, updateItem,
|
|
@@ -27,11 +31,25 @@ const operation : any = computed(()=>{
|
|
|
27
31
|
return Object.assign({},editPad.value?.operation,{canSave,reload,item})
|
|
28
32
|
})
|
|
29
33
|
|
|
34
|
+
const onCreateItem = (item: Record<string, any>,callback?: FormDialogCallback)=>{
|
|
35
|
+
createItem(item,callback).then(()=>{
|
|
36
|
+
useDialog().notify({message: "Data created successfully",type: 'success',title:"Success"})
|
|
37
|
+
emit("create",item,callback)
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const onUpdateItem = (item: Record<string, any>,callback?: FormDialogCallback)=>{
|
|
42
|
+
updateItem(item,callback).then(()=>{
|
|
43
|
+
useDialog().notify({message: "Data updated successfully",type: 'success',title:"Success"})
|
|
44
|
+
emit("update",item,callback)
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
30
48
|
defineExpose({ operation, formPad: editPad.value?.formPad })
|
|
31
49
|
</script>
|
|
32
50
|
|
|
33
51
|
<template>
|
|
34
|
-
<FormEditPad v-bind="$attrs" :form-data="item" ref="editPadRef" @create="
|
|
52
|
+
<FormEditPad v-bind="$attrs" :form-data="item" ref="editPadRef" @create="onCreateItem" @update="onUpdateItem">
|
|
35
53
|
<template #titleToolbar>
|
|
36
54
|
<slot name="titleToolbar" :operation="operation">
|
|
37
55
|
<VToolbarTitle>
|
|
@@ -50,7 +50,7 @@ const props = withDefaults(defineProps<Props & GraphqlModelProps>(), {
|
|
|
50
50
|
onlyOwnerEdit: false,
|
|
51
51
|
})
|
|
52
52
|
|
|
53
|
-
const emit = defineEmits(['open:dialog','close:dialog'])
|
|
53
|
+
const emit = defineEmits(['open:dialog','close:dialog','create','update','delete'])
|
|
54
54
|
const attrs = useAttrs()
|
|
55
55
|
const plainAttrs = computed(() => {
|
|
56
56
|
const returnAttrs = clone(attrs)
|
|
@@ -95,7 +95,25 @@ function openDialogReadonly(item?: object) {
|
|
|
95
95
|
|
|
96
96
|
async function confirmDeleteItem(item: Record<string, any>, callback?: FormDialogCallback) {
|
|
97
97
|
let confirm = await useDialog().confirm({message: "Do you want to delete record?"})
|
|
98
|
-
if (confirm)
|
|
98
|
+
if (confirm) onDeleteItem(item,callback)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const onCreateItem = (item: Record<string, any>,callback?: FormDialogCallback)=>{
|
|
102
|
+
createItem(item,callback).then(()=>{
|
|
103
|
+
emit("create",item,callback)
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const onUpdateItem = (item: Record<string, any>,callback?: FormDialogCallback)=>{
|
|
108
|
+
updateItem(item,callback).then(()=>{
|
|
109
|
+
emit("update",item,callback)
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const onDeleteItem = (item: Record<string, any>,callback?: FormDialogCallback)=>{
|
|
114
|
+
deleteItem(item,callback).then(()=>{
|
|
115
|
+
emit("delete",item,callback)
|
|
116
|
+
})
|
|
99
117
|
}
|
|
100
118
|
|
|
101
119
|
const canEditRow = function (item: Record<string, any>) {
|
|
@@ -301,8 +319,8 @@ defineExpose({ reload,operation })
|
|
|
301
319
|
:fullscreen="dialogFullscreen"
|
|
302
320
|
:initial-data="computedInitialData"
|
|
303
321
|
:form-data="currentItem"
|
|
304
|
-
@create="
|
|
305
|
-
@update="
|
|
322
|
+
@create="onCreateItem"
|
|
323
|
+
@update="onUpdateItem"
|
|
306
324
|
@afterLeave="emit('close:dialog')"
|
|
307
325
|
:saveAndStay="saveAndStay"
|
|
308
326
|
:readonly="isDialogReadonly"
|
|
@@ -89,7 +89,7 @@ export function templateItemToString(inputItem, parentTemplates, dataVariable =
|
|
|
89
89
|
}
|
|
90
90
|
function columnWrapTemplateItemString(item, parentTemplates, dataVariable = "data") {
|
|
91
91
|
let templateString = templateItemToString(item, parentTemplates, dataVariable);
|
|
92
|
-
if (!["Separator", "FormHidden"].includes(item.inputType)) templateString = `<v-col${item.width ? ` cols="${item.width}"` : ""}${item.columnAttributes ? " " + item.columnAttributes : ""}${item.customClass ? ` class="${item.customClass}"` : ""}${item.customStyle ? ` class="${item.customStyle}"` : ""}>${templateString}</v-col>`;
|
|
92
|
+
if (!["Separator", "FormHidden"].includes(item.inputType)) templateString = `<v-col${item.width ? ` cols="${item.width}"` : ""}${item.columnAttributes ? " " + item.columnAttributes : ""} :class="(injectedClass) ? injectedClass['${item.variableName || ""}'] : undefined"${item.customClass ? ` class="${item.customClass}"` : ""}${item.customStyle ? ` class="${item.customStyle}"` : ""}>${templateString}</v-col>`;
|
|
93
93
|
if (["Header", "DocumentForm"].includes(item.inputType)) templateString = `</v-row><v-row dense${item.customClass ? ` class="${item.customClass}"` : ""}${item.customStyle ? ` class="${item.customStyle}"` : ""}>${templateString}</v-row><v-row dense>`;
|
|
94
94
|
return templateString || "";
|
|
95
95
|
}
|
|
@@ -11,6 +11,11 @@ export declare function useRules(): {
|
|
|
11
11
|
lengthGreater: (length: number, customError?: string) => (value: any) => string | true;
|
|
12
12
|
lengthLess: (length: number, customError?: string) => (value: any) => string | true;
|
|
13
13
|
telephone: (customError?: string) => (value: any) => string | true;
|
|
14
|
+
telephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
15
|
+
internationalTelephone: (customError?: string) => (value: any) => string | true;
|
|
16
|
+
internationalTelephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
17
|
+
mobilePhone: (customError?: string) => (value: any) => string | true;
|
|
18
|
+
mobilePhoneSingle: (customError?: string) => (value: any) => string | true;
|
|
14
19
|
email: (customError?: string) => (value: any) => string | true;
|
|
15
20
|
regex: (regex: RegExp | string, customError?: string) => (value: any) => string | true;
|
|
16
21
|
idcard: (customError?: string) => (value: any) => string | true;
|
|
@@ -34,6 +39,11 @@ export declare function useRules(): {
|
|
|
34
39
|
lengthGreater: (length: number, customError?: string) => (value: any) => string | true;
|
|
35
40
|
lengthLess: (length: number, customError?: string) => (value: any) => string | true;
|
|
36
41
|
telephone: (customError?: string) => (value: any) => string | true;
|
|
42
|
+
telephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
43
|
+
internationalTelephone: (customError?: string) => (value: any) => string | true;
|
|
44
|
+
internationalTelephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
45
|
+
mobilePhone: (customError?: string) => (value: any) => string | true;
|
|
46
|
+
mobilePhoneSingle: (customError?: string) => (value: any) => string | true;
|
|
37
47
|
email: (customError?: string) => (value: any) => string | true;
|
|
38
48
|
regex: (regex: RegExp | string, customError?: string) => (value: any) => string | true;
|
|
39
49
|
idcard: (customError?: string) => (value: any) => string | true;
|
|
@@ -57,6 +67,11 @@ export declare function useRules(): {
|
|
|
57
67
|
lengthGreater: (length: number, customError?: string) => (value: any) => string | true;
|
|
58
68
|
lengthLess: (length: number, customError?: string) => (value: any) => string | true;
|
|
59
69
|
telephone: (customError?: string) => (value: any) => string | true;
|
|
70
|
+
telephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
71
|
+
internationalTelephone: (customError?: string) => (value: any) => string | true;
|
|
72
|
+
internationalTelephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
73
|
+
mobilePhone: (customError?: string) => (value: any) => string | true;
|
|
74
|
+
mobilePhoneSingle: (customError?: string) => (value: any) => string | true;
|
|
60
75
|
email: (customError?: string) => (value: any) => string | true;
|
|
61
76
|
regex: (regex: RegExp | string, customError?: string) => (value: any) => string | true;
|
|
62
77
|
idcard: (customError?: string) => (value: any) => string | true;
|
|
@@ -80,6 +95,11 @@ export declare function useRules(): {
|
|
|
80
95
|
lengthGreater: (length: number, customError?: string) => (value: any) => string | true;
|
|
81
96
|
lengthLess: (length: number, customError?: string) => (value: any) => string | true;
|
|
82
97
|
telephone: (customError?: string) => (value: any) => string | true;
|
|
98
|
+
telephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
99
|
+
internationalTelephone: (customError?: string) => (value: any) => string | true;
|
|
100
|
+
internationalTelephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
101
|
+
mobilePhone: (customError?: string) => (value: any) => string | true;
|
|
102
|
+
mobilePhoneSingle: (customError?: string) => (value: any) => string | true;
|
|
83
103
|
email: (customError?: string) => (value: any) => string | true;
|
|
84
104
|
regex: (regex: RegExp | string, customError?: string) => (value: any) => string | true;
|
|
85
105
|
idcard: (customError?: string) => (value: any) => string | true;
|
|
@@ -14,7 +14,12 @@ export function useRules() {
|
|
|
14
14
|
const length = (length2, customError = `Length must be ${length2}`) => (value) => condition(!value || value.length == length2, customError);
|
|
15
15
|
const lengthGreater = (length2, customError = `Length must be greater than ${length2}`) => (value) => condition(!value || value.length >= length2, customError);
|
|
16
16
|
const lengthLess = (length2, customError = `Length must be less than ${length2}`) => (value) => condition(!value || value.length <= length2, customError);
|
|
17
|
-
const telephone = (customError = "Invalid telephone number") => (value) => condition(!value || /^(?:\s*(?:
|
|
17
|
+
const telephone = (customError = "Invalid telephone number") => (value) => condition(!value || /^(?:\s*(?:\+66|0)\s?(?:[2-57](?:[\s-]?\d){7}|[689](?:[\s-]?\d){8})(?:#\d{1,5})?\s*(?:\([^()]+\)\s*)?(?:,(?=\s*\+?6?0)|,|$))*$/.test(value), customError);
|
|
18
|
+
const telephoneSingle = (customError = "Invalid telephone number") => (value) => condition(!value || /^\s*(?:\+66|0)\s?(?:[2-57](?:[\s-]?\d){7}|[689](?:[\s-]?\d){8})(?:#\d{1,5})?\s*(?:\([^()]+\)\s*)?$/.test(value), customError);
|
|
19
|
+
const internationalTelephone = (customError = "Invalid telephone number") => (value) => condition(!value || /^(?:\s*(?:\+?\d{1,3}[-\s]?)?(?:0?\d{1,4}[-\s]?)?\d{3,4}[-\s]?\d{3,4}(?:#\d{1,5})?\s*(?:\([^()]+\)\s*)?(?:,(?=\s*\+?\d)|,|$))*$/.test(value), customError);
|
|
20
|
+
const internationalTelephoneSingle = (customError = "Invalid telephone number") => (value) => condition(!value || /^\s*(?:\+?\d{1,3}[-\s]?)?(?:0?\d{1,4}[-\s]?)?\d{3,4}[-\s]?\d{3,4}(?:#\d{1,5})?\s*(?:\([^()]+\)\s*)?$/.test(value), customError);
|
|
21
|
+
const mobilePhone = (customError = "Invalid telephone number") => (value) => condition(!value || /^(?:\s*(?:\+66|0)\s?(?:6\d{8}|8\d{8}|9\d{8})\s*(?:,(?=\s*\+?6?0)|,|$))*$/.test(value), customError);
|
|
22
|
+
const mobilePhoneSingle = (customError = "Invalid telephone number") => (value) => condition(!value || /^\s*(?:\+66|0)\s?(?:6\d{8}|8\d{8}|9\d{8})\s*$/.test(value), customError);
|
|
18
23
|
const email = (customError = "Invalid email address") => (value) => condition(!value || /^([\w\-.]+)@([\w\-.]+)\.([a-z]{2,5})$/i.test(value), customError);
|
|
19
24
|
const regex = (regex2, customError = "Invalid format") => (value) => condition(!value || new RegExp(regex2).test(value), customError);
|
|
20
25
|
const idcard = (customError = "Invalid ID Card format") => (value) => condition(!value || /^\d{13}$/.test(value) && (11 - [...value].slice(0, 12).reduce((sum, n, i) => sum + +n * (13 - i), 0) % 11) % 10 === +value[12], customError);
|
|
@@ -38,6 +43,11 @@ export function useRules() {
|
|
|
38
43
|
lengthGreater,
|
|
39
44
|
lengthLess,
|
|
40
45
|
telephone,
|
|
46
|
+
telephoneSingle,
|
|
47
|
+
internationalTelephone,
|
|
48
|
+
internationalTelephoneSingle,
|
|
49
|
+
mobilePhone,
|
|
50
|
+
mobilePhoneSingle,
|
|
41
51
|
email,
|
|
42
52
|
regex,
|
|
43
53
|
idcard,
|