Skip to content

Instantly share code, notes, and snippets.

@peteleco
Last active September 12, 2022 16:25
Show Gist options
  • Select an option

  • Save peteleco/c0badd3255b05371d34f4b7c10689653 to your computer and use it in GitHub Desktop.

Select an option

Save peteleco/c0badd3255b05371d34f4b7c10689653 to your computer and use it in GitHub Desktop.

Revisions

  1. peteleco revised this gist Jan 5, 2021. 1 changed file with 15 additions and 0 deletions.
    15 changes: 15 additions & 0 deletions vMobile.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    // Validate mobile numbers in Brazil
    const vMobile = (mobile) => {
    const m = mobile.replace(/\+|\)|\(| |-/g, '');
    const regex = /^55[1-9]{2}9[1-9][0-9]{7}$/;
    const ddd = m.substring(3, 5);

    const ddds = ['11', '12', '13', '14', '15', '16', '17', '18', '19', '21', '22', '24', '27', '28', '31', '32', '33', '34', '35', '37', '38', '41', '42', '43', '44', '45', '46', '47', '48', '49', '51', '53', '54', '55', '61', '62', '63', '64', '65', '66', '67', '68', '69', '71', '73', '74', '75', '77', '79', '81', '82', '83', '84', '85', '86', '87', '88', '89', '91', '92', '93', '94', '95', '96', '97', '98', '99'];
    if (ddds.indexOf(ddd) < 0) {
    return false;
    }

    return regex.test(m);
    }

    export default vMobile ;
  2. peteleco created this gist Oct 7, 2020.
    128 changes: 128 additions & 0 deletions Create.vue
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,128 @@
    <template>
    <app-layout>
    <template #header>
    <h2 class="font-semibold text-xl text-gray-800 leading-tight">
    Cadastrar Novo Cliente
    </h2>
    <breadcrumb slot="breadcrumb" :items="breadcrumbItems"></breadcrumb>
    </template>
    <div class="py-12">
    <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
    <jet-form-section @submitted="create">
    <template #title>
    {{$t('PAGES.CLIENTS.CREATE.form_title')}}
    </template>

    <template #description>
    {{$t('PAGES.CLIENTS.CREATE.form_description')}}
    </template>

    <template #form>
    <!-- Name -->
    <div class="col-span-6 sm:col-span-4">
    <jet-label for="name" value="Name" />
    <jet-input id="name" type="text" class="mt-1 block w-full" aria-required="true" v-model="form.name" autocomplete="name" />
    <jet-input-error :message="form.error('name')" class="mt-2" />
    </div>
    <!-- Mobile -->
    <div class="col-span-6 sm:col-span-4">
    <jet-label for="mobile" value="Celular do cliente"/>
    <jet-input-validation :error-bag="form.error('mobile')" :error-length="18" :value="form.mobile" :v-function="vMobile" ref="mobileWrapper">
    <template #input="slotProps">
    <jet-input id="mobile" type="tel"
    v-facade="[$t('MASKS.MOBILE')]"
    class="mt-1 block w-full"
    :class="{'focus:border-gray-400': !slotProps.displayError, 'border-danger-300 focus:border-danger-500': slotProps.displayError}"
    aria-required="true" v-model="form.mobile" :aria-placeholder="$t('PAGES.CLIENTS.CREATE.aria_mobile_placeholder')" :placeholder="$t('PAGES.CLIENTS.CREATE.mobile_placeholder')" autocomplete="off"/>
    </template>

    <template #valid>
    <svg xmlns="http://www.w3.org/2000/svg" fill="none" class="w-6 h-6 text-success" viewBox="0 0 24 24" stroke="currentColor">
    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 10h4.764a2 2 0 011.789 2.894l-3.5 7A2 2 0 0115.263 21h-4.017c-.163 0-.326-.02-.485-.06L7 20m7-10V5a2 2 0 00-2-2h-.095c-.5 0-.905.405-.905.905 0 .714-.211 1.412-.608 2.006L7 11v9m7-10h-2M7 20H5a2 2 0 01-2-2v-6a2 2 0 012-2h2.5" />
    </svg>
    </template>
    <template #invalid>
    <svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-danger" fill="none" viewBox="0 0 24 24" stroke="currentColor">
    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
    </svg>
    </template>
    </jet-input-validation>
    <jet-input-error :message="form.error('mobile')" class="mt-2" />
    </div>

    </template>

    <template #actions>
    <jet-action-message :on="form.recentlySuccessful" class="mr-3">
    Saved.
    </jet-action-message>

    <jet-button :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
    Save
    </jet-button>
    </template>
    </jet-form-section>
    </div>
    </div>
    </app-layout>
    </template>

    <script>
    import {JetInput, JetButton, JetFormSection, JetInputError, JetLabel, JetActionMessage, JetSecondaryButton} from '@/Jetstream';
    import AppLayout from '@/Layouts/AppLayout';
    import {Breadcrumb} from '@/Components';
    import {JetInputValidation} from '@/Chama/Jetstream';
    import {vMobile} from '@/Chama/Validations';
    export default {
    name: "Create",
    components: {
    AppLayout,
    Breadcrumb,
    JetActionMessage,
    JetButton,
    JetFormSection,
    JetInputError,
    JetLabel,
    JetSecondaryButton,
    JetInput,
    JetInputValidation
    },
    computed: {
    breadcrumbItems() {
    return [
    {route: this.route('app.clients'), label: this.$t('BREADCRUMB.clients')},
    {route: this.route('app.clients.create'), label: this.$t('BREADCRUMB.create')},
    ];
    }
    },
    data() {
    return {
    form: this.$inertia.form({
    '_method': 'POST',
    name: this.name,
    mobile: this.mobile,
    photo: null,
    }, {
    bag: 'default',
    resetOnSuccess: false,
    }),
    }
    },
    methods: {
    vMobile,
    create() {
    this.form.post(this.route('app.clients.post'), {
    preserveScroll: true
    });
    },
    }
    }
    </script>

    <style scoped>
    </style>
    126 changes: 126 additions & 0 deletions InputValidation.vue
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,126 @@
    <template>
    <span class="flex flex-row mb-1 relative" ref="inputValidation">
    <slot name="input" v-bind:displayError="displayError"></slot>

    <span class="absolute right-0 flex items-center py-3 px-4 h-full">
    <template v-if="isValid">
    <slot name="valid">
    <svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
    </svg>
    </slot>
    </template>
    <template v-if="displayError">
    <slot name="invalid">
    <svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
    d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
    </svg>
    </slot>
    </template>

    </span>
    </span>
    </template>

    <script>
    export default {
    name: 'InputValidation',
    props: {
    /**
    * The value from input
    */
    value: {
    type: String,
    default: ""
    },
    /**
    *The function that will be used
    * at validation
    */
    vFunction: {
    type: Function,
    default: (val) => true
    },
    /**
    * After type how many characters
    * the error can be displayed
    */
    errorLength: {
    type: Number,
    default: 0
    },
    errorBag: {
    default: false
    }
    },
    watch: {
    value: {
    // the callback will be called immediately after the start of the observation
    immediate: true,
    handler(val, oldVal) {
    this.handleValueUpdates(val);
    }
    }
    },
    computed: {
    isValid() {
    return this.valid;
    },
    /**
    * Tells whether the error can already be displayed
    */
    displayError() {
    if (this.hasBagError && !this.valid) {
    return true;
    }
    return (!this.valid && this.hasMinLength);
    },
    /**
    * Checks if enough has been entered
    * to display error
    * @returns {boolean}
    */
    hasMinLength() {
    return (this.value.length >= this.errorLength);
    },
    /**
    * Has error from server request
    */
    hasBagError() {
    return (this.errorBag.length > 0);
    }
    },
    data() {
    return {
    valid: false,
    }
    },
    methods: {
    /**
    * Every time that value prop changes this function will be called
    * @param val
    */
    handleValueUpdates(val) {
    if (this.vFunction(val) === true) {
    return this.setAsValid();
    }
    return this.setAsInvalid();
    },
    setAsValid() {
    this.valid = true;
    // this.$emit('form-input-validation', this.name, this.valid = true);
    },
    setAsInvalid() {
    // this.$emit('form-input-validation', this.name, false);
    this.valid = false;
    },
    }
    }
    </script>

    <style scoped>
    </style>