How can I make this code work for expiry date TextInput which includes (mm/yy) model? - react-native

I want to create a checkout form which includes expiry date TextInput. It will look like a this (MM/YY). After adding first 2 digits it will automatically add / then the person can type last 2 digits for the year. I found this code on the other question. But it doesn't work. When you type inside the form nothing is typed. Here is the code. How can I make this code work as needed?
constructor() {
super()
this.state = {
isReady: false
}
}
componentDidMount() {
this.setState({
isReady: true
})
}
onChange(text) {
let newText = '';
let numbers = '0123456789';
for (var i = 0; i < text.length; i++) {
if ( numbers.indexOf(text[i]) > -1 ) {
newText = newText + text[i];
}
}
this.setState({myNumber: newText})
}
formatFunction(cardExpiry = ""){
//expiryDate will be in the format MMYY, so don't make it smart just format according to these requirements, if the input has less than 2 character return it otherwise append `/` character between 2nd and 3rd letter of the input.
if(cardExpiry.length < 2){
return cardExpiry;
}
else{
return cardExpiry.substr(0, 2) + "/" + (cardExpiry.substr(2) || "")
}
}
inputToValue(inputText){
//if the input has more than 5 characters don't set the state
if(inputText.length < 6){
const tokens = inputText.split("/");
// don't set the state if there is more than one "/" character in the given input
if(tokens.length < 3){
const month = Number(tokens[1]);
const year = Number(tokens[2]);
//don't set the state if the first two letter is not a valid month
if(month >= 1 && month <= 12){
let cardExpiry = month + "";
//I used lodash for padding the month and year with zero
if(month > 1 || tokens.length === 2){
// user entered 2 for the month so pad it automatically or entered "1/" convert it to 01 automatically
cardExpiry = _.padStart(month, 2, "0");
}
//disregard changes for invalid years
if(year > 1 && year <= 99){
cardExpiry += year;
}
this.setState({cardExpiry});
}
}
}
}
render (){
let {cardExpiry} = this.state;
return (
<Image style={styles.image} source={require('../img/cover.jpg')}
>
<Content style={styles.content}>
<Form>
<Item >
<Icon active name='card'/>
<Input keyboardType='numeric' maxLength={16} placeholder='Card Number'
onChangeText = {(text)=> this.onChange(text)}
value = {this.state.myNumber}/>
</Item>
<Grid>
<Row>
<Col>
<Item style={{ marginBottom:10}}>
<Icon active name='calendar' />
<Input keyboardType='numeric' placeholder='MM/YY'
value = {this.formatFunction(cardExpiry)}
onChangeText={this.inputToValue.bind(this)}/>
</Item>
</Col>
<Col>
<Item style={{ marginBottom:10}}>
<Icon active name='lock' />
<Input maxLength={3} secureTextEntry={true} placeholder='CVV'/>
</Item>
</Col>
</Row>
</Grid>

Use this code to handle your problem:
constructor(props) {
super(props);
this.state = { text: '' };
}
handleChange = (text) => {
let textTemp = text;
if (textTemp[0] !== '1' && textTemp[0] !== '0') {
textTemp = '';
}
if (textTemp.length === 2) {
if (parseInt(textTemp.substring(0, 2)) > 12 || parseInt(textTemp.substring(0, 2)) == 0) {
textTemp = textTemp[0];
} else if (this.state.text.length === 2) {
textTemp += '/';
} else {
textTemp = textTemp[0];
}
}
this.setState({text: textTemp})
}
render() {
return (
<TextInput
keyboardType={'numeric'}
onChangeText={this.handleChange}
value={this.state.text}
maxLength={5}
/>
);
}

After searching a lot for Picker with Month/Year, for the time being i have created a logic for the Expiry date.
Hope this will help somebody.
const onCardExpiryDateChange = (prevValue:string, currentValue: string) => {
if (currentValue?.includes(',') || currentValue?.includes('-') || currentValue?.includes('.')) {
return prevValue
} else {
let textTemp = currentValue
if (textTemp[0] !== '0' && textTemp[0] !== '1' && textTemp[0] !== '2' && textTemp[0] !== '3') {
textTemp = '';
} else if ((prevValue?.length === 5) && currentValue.length === prevValue.length-1) {
textTemp = textTemp?.slice(0, -3)
} else if (textTemp.length === 6 && (textTemp[5] == '0' || textTemp[5] == '1')){
textTemp = textTemp?.slice(0, -1)
}
else if (textTemp.length === 7 && textTemp[6] == '0') {
textTemp = textTemp?.slice(0, -1)
} else if (textTemp.length === 2) {
if (parseInt(textTemp?.substring(0, 2)) > 12 || parseInt(textTemp?.substring(0, 2)) == 0) {
textTemp = textTemp?.slice(0, -1)
} else if (textTemp?.length === 2) {
textTemp += ' / ';
} else {
textTemp = textTemp[0];
}
}
return textTemp
}
}

As #AndroConsis pointed out in #Vahid Boreiri's answer, the only problem with adding '/' after length 2 is when deleting the expiry date it keeps adding '/'. To fix this, one can add a conditional backspaceFlag.
const [backspaceFlag, setBackspaceFlag] = React.useState(false);
const [expiratoinDate, setExpirationDate] = React.useState('');
const handleExpirationDate = (text) => {
let textTemp = text;
if (textTemp[0] !== '1' && textTemp[0] !== '0') {
textTemp = '';
}
if (textTemp.length === 2) {
if (parseInt(textTemp.substring(0, 2)) > 12 || parseInt(textTemp.substring(0, 2)) == 0) {
textTemp = textTemp[0];
} else if (text.length === 2 && !backspaceFlag) {
textTemp += '/';
setBackspaceFlag(true);
} else if (text.length === 2 && backspaceFlag) {
textTemp = textTemp[0];
setBackspaceFlag(false);
} else {
textTemp = textTemp[0];
}
}
setExpirationDate(textTemp);
};

const [expiratoinDate, setExpirationDate] = useState(''); const [backspaceFlag, setBackspaceFlag] = useState(false);
const handleExpirationDate = (text) => {
if(backspaceFlag===false){
if(text.length==2){ setExpirationDate(text+"/"); setBackspaceFlag(true) }
`else{
setExpirationDate(text)
}`
}
else{
if(text.length==2){
let text2=expiratoinDate.slice(0,1)
`setExpirationDate(text2);`
`setBackspaceFlag(false)
}`
`else{
setExpirationDate(text)
}`
}
`};`

Adding an answer that resolves not being able to delete the '/' in above solution.
const setExpiry = (e) => {
const { name, value } = e.target;
var v = value;
if (v.includes('/') == false) {
if (v.length === 4) {
var a = v.substr(0, 2);
var ae = v.charAt(v.length - 2) + v.charAt(v.length - 1);
e.target.value = a + '/' + ae;
}
}
}

Related

Vuejs-pdf print

I'm using vuejs-pdf to print some pages of my pdf and the print is not show the characters :
that's the code i'm using :
<button #click="$refs.myPdfComponent.print(100,pages)">Print </button>
<pdf v-for="i in pages" :key="i" ref="newpdf" :src="'pdf/'+src" :page="i" class="rounded border
border-info mb-4" :rotate="rotate" #progress="loadedRatio = $event" #error="error" #num-pages="numPages = $event" #link-clicked="page = $event" > </pdf>
and the pdf i'm printing is myPdfComponent the newpdf is the only the pages i need :
<pdf v-if="show" ref="myPdfComponent" class="rounded border border-info mb-4" :src="'pdf/'+src"
:page="page" :rotate="rotate" #progress="loadedRatio = $event" #error="error" #num-pages="numPages =
$event" #link-clicked="page = $event"></pdf>
Open the vue-pdf plugin directory node_modules/vue-pdf/src/pdfjsWrapper.js
and replace
import { PDFLinkService } from 'pdfjs-dist/es5/web/pdf_viewer';
var pendingOperation = Promise.resolve();
export default function(PDFJS) {
function isPDFDocumentLoadingTask(obj) {
return typeof(obj) === 'object' && obj !== null && obj.__PDFDocumentLoadingTask === true;
// or: return obj.constructor.name === 'PDFDocumentLoadingTask';
}
function createLoadingTask(src, options) {
var source;
if ( typeof(src) === 'string' )
source = { url: src };
else if ( src instanceof Uint8Array )
source = { data: src };
else if ( typeof(src) === 'object' && src !== null )
source = Object.assign({}, src);
else
throw new TypeError('invalid src type');
// source.verbosity = PDFJS.VerbosityLevel.INFOS;
// source.pdfBug = true;
// source.stopAtErrors = true;
if ( options && options.withCredentials )
source.withCredentials = options.withCredentials;
var loadingTask = PDFJS.getDocument(source);
loadingTask.__PDFDocumentLoadingTask = true; // since PDFDocumentLoadingTask is not public
if ( options && options.onPassword )
loadingTask.onPassword = options.onPassword;
if ( options && options.onProgress )
loadingTask.onProgress = options.onProgress;
return loadingTask;
}
function PDFJSWrapper(canvasElt, annotationLayerElt, emitEvent) {
var pdfDoc = null;
var pdfPage = null;
var pdfRender = null;
var canceling = false;
canvasElt.getContext('2d').save();
function clearCanvas() {
canvasElt.getContext('2d').clearRect(0, 0, canvasElt.width, canvasElt.height);
}
function clearAnnotations() {
while ( annotationLayerElt.firstChild )
annotationLayerElt.removeChild(annotationLayerElt.firstChild);
}
this.destroy = function() {
if ( pdfDoc === null )
return;
// Aborts all network requests and destroys worker.
pendingOperation = pdfDoc.destroy();
pdfDoc = null;
}
this.getResolutionScale = function() {
return canvasElt.offsetWidth / canvasElt.width;
}
this.printPage = function(dpi, pageNumberOnly) {
if ( pdfPage === null )
return;
// 1in == 72pt
// 1in == 96px
var PRINT_RESOLUTION = dpi === undefined ? 150 : dpi;
var PRINT_UNITS = PRINT_RESOLUTION / 72.0;
var CSS_UNITS = 96.0 / 72.0;
/*var iframeElt = document.createElement('iframe');
function removeIframe() {
iframeElt.parentNode.removeChild(iframeElt);
}*/
var printContainerElement = document.createElement('div');
printContainerElement.setAttribute('id', 'print-container')
function removePrintContainer() {
printContainerElement.parentNode.removeChild(printContainerElement);
}
new Promise(function(resolve, reject) {
/*
iframeElt.frameBorder = '0';
iframeElt.scrolling = 'no';
iframeElt.width = '0px;'
iframeElt.height = '0px;'
iframeElt.style.cssText = 'position: absolute; top: 0; left: 0';
iframeElt.onload = function() {
resolve(this.contentWindow);
}
window.document.body.appendChild(iframeElt);*/
printContainerElement.frameBorder = '0';
printContainerElement.scrolling = 'no';
printContainerElement.width = '0px;'
printContainerElement.height = '0px;'
printContainerElement.style.cssText = 'position: absolute; top: 0; left: 0';
window.document.body.appendChild(printContainerElement);
resolve(window)
})
.then(function(win) {
win.document.title = '';
return pdfDoc.getPage(1)
.then(function(page) {
var viewport = page.getViewport({ scale: 1 });
//win.document.head.appendChild(win.document.createElement('style')).textContent =
printContainerElement.appendChild(win.document.createElement('style')).textContent =
'#supports ((size:A4) and (size:1pt 1pt)) {' +
'#page { margin: 1pt; size: ' + ((viewport.width * PRINT_UNITS) / CSS_UNITS) + 'pt ' + ((viewport.height * PRINT_UNITS) / CSS_UNITS) + 'pt; }' +
'}' +
'#print-canvas { display: none }' +
'#media print {' +
'body { margin: 0 }' +
'canvas { page-break-before: avoid; page-break-after: always; page-break-inside: avoid }' +
'#print-canvas { page-break-before: avoid; page-break-after: always; page-break-inside: avoid; display: block }' +
'body > *:not(#print-container) { display: none; }' +
'}'+
'#media screen {' +
'body { margin: 0 }' +
'}'+
''
return win;
})
})
.then(function(win) {
var allPages = [];
for ( var pageNumber = 1; pageNumber <= pdfDoc.numPages; ++pageNumber ) {
if ( pageNumberOnly !== undefined && pageNumberOnly.indexOf(pageNumber) === -1 )
continue;
allPages.push(
pdfDoc.getPage(pageNumber)
.then(function(page) {
var viewport = page.getViewport({ scale: 1 });
//var printCanvasElt = win.document.body.appendChild(win.document.createElement('canvas'));
var printCanvasElt = printContainerElement.appendChild(win.document.createElement('canvas'));
printCanvasElt.setAttribute('id', 'print-canvas')
printCanvasElt.width = (viewport.width * PRINT_UNITS);
printCanvasElt.height = (viewport.height * PRINT_UNITS);
return page.render({
canvasContext: printCanvasElt.getContext('2d'),
transform: [ // Additional transform, applied just before viewport transform.
PRINT_UNITS, 0, 0,
PRINT_UNITS, 0, 0
],
viewport: viewport,
intent: 'print'
}).promise;
})
);
}
Promise.all(allPages)
.then(function() {
win.focus(); // Required for IE
if (win.document.queryCommandSupported('print')) {
win.document.execCommand('print', false, null);
} else {
win.print();
}
removePrintContainer();
})
.catch(function(err) {
removePrintContainer();
emitEvent('error', err);
})
})
}
this.renderPage = function(rotate) {
if ( pdfRender !== null ) {
if ( canceling )
return;
canceling = true;
pdfRender.cancel();
return;
}
if ( pdfPage === null )
return;
var pageRotate = (pdfPage.rotate === undefined ? 0 : pdfPage.rotate) + (rotate === undefined ? 0 : rotate);
var scale = canvasElt.offsetWidth / pdfPage.getViewport({ scale: 1 }).width * (window.devicePixelRatio || 1);
var viewport = pdfPage.getViewport({ scale: scale, rotation:pageRotate });
emitEvent('page-size', viewport.width, viewport.height, scale);
canvasElt.width = viewport.width;
canvasElt.height = viewport.height;
pdfRender = pdfPage.render({
canvasContext: canvasElt.getContext('2d'),
viewport: viewport
});
annotationLayerElt.style.visibility = 'hidden';
clearAnnotations();
var viewer = {
scrollPageIntoView: function(params) {
emitEvent('link-clicked', params.pageNumber)
},
};
var linkService = new PDFLinkService();
linkService.setDocument(pdfDoc);
linkService.setViewer(viewer);
pendingOperation = pendingOperation.then(function() {
var getAnnotationsOperation =
pdfPage.getAnnotations({ intent: 'display' })
.then(function(annotations) {
PDFJS.AnnotationLayer.render({
viewport: viewport.clone({ dontFlip: true }),
div: annotationLayerElt,
annotations: annotations,
page: pdfPage,
linkService: linkService,
renderInteractiveForms: false
});
});
var pdfRenderOperation =
pdfRender.promise
.then(function() {
annotationLayerElt.style.visibility = '';
canceling = false;
pdfRender = null;
})
.catch(function(err) {
pdfRender = null;
if ( err instanceof PDFJS.RenderingCancelledException ) {
canceling = false;
this.renderPage(rotate);
return;
}
emitEvent('error', err);
}.bind(this))
return Promise.all([getAnnotationsOperation, pdfRenderOperation]);
}.bind(this));
}
this.forEachPage = function(pageCallback) {
var numPages = pdfDoc.numPages;
(function next(pageNum) {
pdfDoc.getPage(pageNum)
.then(pageCallback)
.then(function() {
if ( ++pageNum <= numPages )
next(pageNum);
})
})(1);
}
this.loadPage = function(pageNumber, rotate) {
pdfPage = null;
if ( pdfDoc === null )
return;
pendingOperation = pendingOperation.then(function() {
return pdfDoc.getPage(pageNumber);
})
.then(function(page) {
pdfPage = page;
this.renderPage(rotate);
emitEvent('page-loaded', page.pageNumber);
}.bind(this))
.catch(function(err) {
clearCanvas();
clearAnnotations();
emitEvent('error', err);
});
}
this.loadDocument = function(src) {
pdfDoc = null;
pdfPage = null;
emitEvent('num-pages', undefined);
if ( !src ) {
canvasElt.removeAttribute('width');
canvasElt.removeAttribute('height');
clearAnnotations();
return;
}
// wait for pending operation ends
pendingOperation = pendingOperation.then(function() {
var loadingTask;
if ( isPDFDocumentLoadingTask(src) ) {
if ( src.destroyed ) {
emitEvent('error', new Error('loadingTask has been destroyed'));
return
}
loadingTask = src;
} else {
loadingTask = createLoadingTask(src, {
onPassword: function(updatePassword, reason) {
var reasonStr;
switch (reason) {
case PDFJS.PasswordResponses.NEED_PASSWORD:
reasonStr = 'NEED_PASSWORD';
break;
case PDFJS.PasswordResponses.INCORRECT_PASSWORD:
reasonStr = 'INCORRECT_PASSWORD';
break;
}
emitEvent('password', updatePassword, reasonStr);
},
onProgress: function(status) {
var ratio = status.loaded / status.total;
emitEvent('progress', Math.min(ratio, 1));
}
});
}
return loadingTask.promise;
})
.then(function(pdf) {
pdfDoc = pdf;
emitEvent('num-pages', pdf.numPages);
emitEvent('loaded');
})
.catch(function(err) {
clearCanvas();
clearAnnotations();
emitEvent('error', err);
})
}
annotationLayerElt.style.transformOrigin = '0 0';
}
return {
createLoadingTask: createLoadingTask,
PDFJSWrapper: PDFJSWrapper,
}
}

How to set Generic search on more than one item in react-native

I am using a search functionality where I search the leave from LeaveType and it works fine but I want to search for Status also, the item contains Status.
How the search function will work on both LeaveType and Status.
What i have tried :
const itemData = item.LeaveType ? item.LeaveType.toUpperCase() : ''.toUpperCase() || item.Status ? item.Status.toUpperCase() : ''.toUpperCase();
I am using this function
SearchFilterFunction(value) {
const newData = this.state.display.filter(function(item) {
const itemData = item.LeaveType ? item.LeaveType.toUpperCase() : ''.toUpperCase();
const textData = value.toUpperCase();
return itemData.indexOf(textData) > -1;
});
this.setState({
response: newData,
value: value,
});
}
can anyone know what wrong I'm doing or what is missing here?
this code works for me
SearchFilterFunction(value) {
const newData = this.state.display.filter(function(item) {
//const itemData = item.LeaveType || item.Status ? item.LeaveType.toUpperCase() || item.Status.toUpperCase() : ''.toUpperCase() || ''.toUpperCase();
const leavetypeData = item.LeaveType ? item.LeaveType.toUpperCase() : ''.toUpperCase();
const statusData = item.Status ? item.Status.toUpperCase() : ''.toUpperCase();
const stData = item.StartDate ? (moment(item.StartDate).format("dd MMM yyyy")) : '';
const edData = item.EndDate ? (moment(item.EndDate).format("dd MMM yyyy")) : '';
const reasonData = item.Reason ? (item.Reason).toUpperCase() : '';
const textData = value.toUpperCase();
return (leavetypeData.indexOf(textData) > -1 || statusData.indexOf(textData) > -1 || stData.toUpperCase().indexOf(textData) > -1
|| edData.toUpperCase().indexOf(textData) > -1 || reasonData.indexOf(textData) > -1);
});
this.setState({
response: newData,
value: value,
});
}
this is my function. Its work 3 param search.
searchFilter = text => {
const newData = this.state.allContacts.filter(item => {
const listItem = `${item.name.first.toLowerCase()} ${item.name.last.toLowerCase()} ${item.location.state.toLowerCase()}`;
return listItem.indexOf(text.toLowerCase()) > -1;
});
this.setState({
contacts: newData,
});
};

Vue.js - Element UI - get the state of form validation

Steps to reproduce
The recurrence link is this: https://stackblitz.com/edit/typescript-vuejs-element-3kko7a
password input 2
username input 11
Change username to 2// should be able to submit, but not
Expected: formvalid = true
Validate Code here:
checkForm() {
// console.log('validate runs');
// #ts-ignore
const fields = this.$refs.ruleForm.fields;
if (fields.find((f) => f.validateState === 'validating')) {
setTimeout(() => {
this.checkForm();
}, 100);
}
this.formValid = fields.reduce((acc, f) => {
const valid = (f.isRequired && f.validateState === 'success');
const notErroring = (!f.isRequired && f.validateState !== 'error');
return acc && (valid || notErroring);
}, true);
console.log('valid:', this.$data.formValid);
}
Basically you watch ruleForm - so everytime ruleForm changes you trigger checkform - but your validtor triggers on blur after you set ruleForm so you first test then turn valid. change this into a getter:
get formValid(){
const fields = this.$refs.ruleForm.fields || [];
if (fields.find((f) => f.validateState === 'validating')) {
setTimeout(() => {
this.checkForm();
}, 100);
}
return fields.reduce((acc, f) => {
const valid = (f.isRequired && f.validateState === 'success');
const notErroring = (!f.isRequired && f.validateState !== 'error');
return acc && (valid || notErroring);
}, fields.length > 0);
}

can not read property 'arrayOfDay1' of null

how to fix it?
i check array not null and go to if
but my app get error
if (this.state.arrayOfDay1.length === 0 || this.state.arrayOfDay1 === 'undefined') {
console.log(18);
var result = (this.state.arrayOfDay1).includes(i + 1);
if (result === true) {
state = 1;
// pic = require('../upload/see.png');
// this.setState({ pic: require('../upload/see.png') });
// this.setState({ key: true });
} else {
state = 0;
// pic = require('../upload/notSee.png');
// this.setState({ pic: require('../upload/notSee.png') });
}
}else {
state = 0;
console.log(1115);
}
enter image description here
enter image description here
thanks
:))))
edited
i find my problem.
i forgot to insert this before state
nicccce
Change the if condition to
if (this.state.arrayOfDay1.length != 0 && this.state.arrayOfDay1 != undefined && this.state.arrayOfDay1.length != null) {
console.log(18);
var result = (this.state.arrayOfDay1).includes(i + 1);
if (result === true) {
state = 1;
// pic = require('../upload/see.png');
// this.setState({ pic: require('../upload/see.png') });
// this.setState({ key: true });
} else {
state = 0;
// pic = require('../upload/notSee.png');
// this.setState({ pic: require('../upload/notSee.png') });
}
}else {
state = 0;
console.log(1115);
}
if(this.state.arrayOfDay1.length !== 0 && this.state.arrayOfDay1 !== undefined ) {
console.log(18);
var result = (this.state.arrayOfDay1).includes(i + 1);
if (result === true) {
state = 1;
// pic = require('../upload/see.png');
// this.setState({ pic: require('../upload/see.png') });
// this.setState({ key: true });
} else {
state = 0;
// pic = require('../upload/notSee.png');
// this.setState({ pic: require('../upload/notSee.png') });
}
}else {
state = 0;
console.log(1115);
}

how to change the phone number format in Textinput using react-native

i want the phone number(work Phone) format to be as shown in the below image, using react-native,can any one help how to work out it,any help much appreciated
You can achieve this with regular expressions... This will format like (555) 222-9999
onTextChange(text) {
var cleaned = ('' + text).replace(/\D/g, '')
var match = cleaned.match(/^(1|)?(\d{3})(\d{3})(\d{4})$/)
if (match) {
var intlCode = (match[1] ? '+1 ' : ''),
number = [intlCode, '(', match[2], ') ', match[3], '-', match[4]].join('');
this.setState({
phoneNum: number
});
return;
}
this.setState({
phoneNum: text
});
}
Then on the <TextInput>...
<TextInput
onChangeText={(text) => this.onTextChange(text) }
value={this.state.phoneNum}
textContentType='telephoneNumber'
dataDetectorTypes='phoneNumber'
keyboardType='phone-pad'
maxLength={14}
/>
This is a slightly more involved solution, but it:
Accounts for when the user is backspacing
Formats as they type (e.g. if they only have two digits, it formats as (55 or 5 digits as (555) 55, or 6 as (555) 555-)
function formatPhoneNumber (text, previousText) {
if (!text) return text
const deleting = previousText && previousText.length > text.length
if (deleting) {
return text
}
let cleaned = text.replace(/\D/g, '') // remove non-digit characters
let match = null
if (cleaned.length > 0 && cleaned.length < 2) {
return `(${cleaned}`
} else if (cleaned.length == 3) {
return `(${cleaned}) `
} else if (cleaned.length > 3 && cleaned.length < 5) {
match = cleaned.match(/(\d{3})(\d{1,3})$/)
if (match) {
return `(${match[1]}) ${match[2]}`
}
} else if (cleaned.length == 6) {
match = cleaned.match(/(\d{3})(\d{3})$/)
if (match) {
return `(${match[1]}) ${match[2]}-`
}
} else if (cleaned.length > 6) {
match = cleaned.match(/(\d{3})(\d{3})(\d{4})$/)
if (match) {
return `(${match[1]}) ${match[2]}-${match[3]}`
}
}
return text
}