mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-11-03 22:13:18 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			757 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			757 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<template>
 | 
						|
  <BasePage>
 | 
						|
    <form @submit.prevent="submitCustomerData">
 | 
						|
      <BasePageHeader :title="pageTitle">
 | 
						|
        <BaseBreadcrumb>
 | 
						|
          <BaseBreadcrumbItem :title="$t('general.home')" to="dashboard" />
 | 
						|
 | 
						|
          <BaseBreadcrumbItem
 | 
						|
            :title="$tc('customers.customer', 2)"
 | 
						|
            to="/admin/customers"
 | 
						|
          />
 | 
						|
 | 
						|
          <BaseBreadcrumb-item :title="pageTitle" to="#" active />
 | 
						|
        </BaseBreadcrumb>
 | 
						|
 | 
						|
        <template #actions>
 | 
						|
          <div class="flex items-center justify-end">
 | 
						|
            <BaseButton type="submit" :loading="isSaving" :disabled="isSaving">
 | 
						|
              <template #left="slotProps">
 | 
						|
                <BaseIcon name="SaveIcon" :class="slotProps.class" />
 | 
						|
              </template>
 | 
						|
              {{
 | 
						|
                isEdit
 | 
						|
                  ? $t('customers.update_customer')
 | 
						|
                  : $t('customers.save_customer')
 | 
						|
              }}
 | 
						|
            </BaseButton>
 | 
						|
          </div>
 | 
						|
        </template>
 | 
						|
      </BasePageHeader>
 | 
						|
 | 
						|
      <BaseCard class="mt-5">
 | 
						|
        <!-- Basic Info -->
 | 
						|
        <div class="grid grid-cols-5 gap-4 mb-8">
 | 
						|
          <h6 class="col-span-5 text-lg font-semibold text-left lg:col-span-1">
 | 
						|
            {{ $t('customers.basic_info') }}
 | 
						|
          </h6>
 | 
						|
 | 
						|
          <BaseInputGrid class="col-span-5 lg:col-span-4">
 | 
						|
            <BaseInputGroup
 | 
						|
              :label="$t('customers.display_name')"
 | 
						|
              required
 | 
						|
              :error="
 | 
						|
                v$.currentCustomer.name.$error &&
 | 
						|
                v$.currentCustomer.name.$errors[0].$message
 | 
						|
              "
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model="customerStore.currentCustomer.name"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                type="text"
 | 
						|
                name="name"
 | 
						|
                class=""
 | 
						|
                :invalid="v$.currentCustomer.name.$error"
 | 
						|
                @input="v$.currentCustomer.name.$touch()"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :label="$t('customers.primary_contact_name')"
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model.trim="customerStore.currentCustomer.contact_name"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                type="text"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :error="
 | 
						|
                v$.currentCustomer.email.$error &&
 | 
						|
                v$.currentCustomer.email.$errors[0].$message
 | 
						|
              "
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
              :label="$t('customers.email')"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model.trim="customerStore.currentCustomer.email"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                type="text"
 | 
						|
                name="email"
 | 
						|
                :invalid="v$.currentCustomer.email.$error"
 | 
						|
                @input="v$.currentCustomer.email.$touch()"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :label="$t('customers.phone')"
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model.trim="customerStore.currentCustomer.phone"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                type="text"
 | 
						|
                name="phone"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :label="$t('customers.primary_currency')"
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
              :error="
 | 
						|
                v$.currentCustomer.currency_id.$error &&
 | 
						|
                v$.currentCustomer.currency_id.$errors[0].$message
 | 
						|
              "
 | 
						|
              required
 | 
						|
            >
 | 
						|
              <BaseMultiselect
 | 
						|
                v-model="customerStore.currentCustomer.currency_id"
 | 
						|
                value-prop="id"
 | 
						|
                label="name"
 | 
						|
                track-by="name"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                :options="globalStore.currencies"
 | 
						|
                searchable
 | 
						|
                :can-deselect="false"
 | 
						|
                :placeholder="$t('customers.select_currency')"
 | 
						|
                :invalid="v$.currentCustomer.currency_id.$error"
 | 
						|
                class="w-full"
 | 
						|
              >
 | 
						|
              </BaseMultiselect>
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :error="
 | 
						|
                v$.currentCustomer.website.$error &&
 | 
						|
                v$.currentCustomer.website.$errors[0].$message
 | 
						|
              "
 | 
						|
              :label="$t('customers.website')"
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model="customerStore.currentCustomer.website"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                type="url"
 | 
						|
                @input="v$.currentCustomer.website.$touch()"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :label="$t('customers.prefix')"
 | 
						|
              :error="
 | 
						|
                v$.currentCustomer.prefix.$error &&
 | 
						|
                v$.currentCustomer.prefix.$errors[0].$message
 | 
						|
              "
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model="customerStore.currentCustomer.prefix"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                type="text"
 | 
						|
                name="name"
 | 
						|
                class=""
 | 
						|
                :invalid="v$.currentCustomer.prefix.$error"
 | 
						|
                @input="v$.currentCustomer.prefix.$touch()"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
          </BaseInputGrid>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <BaseDivider class="mb-5 md:mb-8" />
 | 
						|
 | 
						|
        <!-- Portal Access-->
 | 
						|
 | 
						|
        <div class="grid grid-cols-5 gap-4 mb-8">
 | 
						|
          <h6 class="col-span-5 text-lg font-semibold text-left lg:col-span-1">
 | 
						|
            {{ $t('customers.portal_access') }}
 | 
						|
          </h6>
 | 
						|
 | 
						|
          <BaseInputGrid class="col-span-5 lg:col-span-4">
 | 
						|
            <div class="md:col-span-2">
 | 
						|
              <p class="text-sm text-gray-500">
 | 
						|
                {{ $t('customers.portal_access_text') }}
 | 
						|
              </p>
 | 
						|
 | 
						|
              <BaseSwitch
 | 
						|
                v-model="customerStore.currentCustomer.enable_portal"
 | 
						|
                class="mt-1 flex"
 | 
						|
              />
 | 
						|
            </div>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              v-if="customerStore.currentCustomer.enable_portal"
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
              :label="$t('customers.portal_access_url')"
 | 
						|
              class="md:col-span-2"
 | 
						|
              :help-text="$t('customers.portal_access_url_help')"
 | 
						|
            >
 | 
						|
              <CopyInputField :token="getCustomerPortalUrl" />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              v-if="customerStore.currentCustomer.enable_portal"
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
              :error="
 | 
						|
                v$.currentCustomer.password.$error &&
 | 
						|
                v$.currentCustomer.password.$errors[0].$message
 | 
						|
              "
 | 
						|
              :label="$t('customers.password')"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model.trim="customerStore.currentCustomer.password"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                :type="isShowPassword ? 'text' : 'password'"
 | 
						|
                name="password"
 | 
						|
                :invalid="v$.currentCustomer.password.$error"
 | 
						|
                @input="v$.currentCustomer.password.$touch()"
 | 
						|
              >
 | 
						|
                <template #right>
 | 
						|
                  <BaseIcon
 | 
						|
                    v-if="isShowPassword"
 | 
						|
                    name="EyeOffIcon"
 | 
						|
                    class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
 | 
						|
                    @click="isShowPassword = !isShowPassword"
 | 
						|
                  />
 | 
						|
                  <BaseIcon
 | 
						|
                    v-else
 | 
						|
                    name="EyeIcon"
 | 
						|
                    class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
 | 
						|
                    @click="isShowPassword = !isShowPassword"
 | 
						|
                  /> </template
 | 
						|
              ></BaseInput>
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              v-if="customerStore.currentCustomer.enable_portal"
 | 
						|
              :error="
 | 
						|
                v$.currentCustomer.confirm_password.$error &&
 | 
						|
                v$.currentCustomer.confirm_password.$errors[0].$message
 | 
						|
              "
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
              label="Confirm Password"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model.trim="customerStore.currentCustomer.confirm_password"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                :type="isShowConfirmPassword ? 'text' : 'password'"
 | 
						|
                name="confirm_password"
 | 
						|
                :invalid="v$.currentCustomer.confirm_password.$error"
 | 
						|
                @input="v$.currentCustomer.confirm_password.$touch()"
 | 
						|
              >
 | 
						|
                <template #right>
 | 
						|
                  <BaseIcon
 | 
						|
                    v-if="isShowConfirmPassword"
 | 
						|
                    name="EyeOffIcon"
 | 
						|
                    class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
 | 
						|
                    @click="isShowConfirmPassword = !isShowConfirmPassword"
 | 
						|
                  />
 | 
						|
                  <BaseIcon
 | 
						|
                    v-else
 | 
						|
                    name="EyeIcon"
 | 
						|
                    class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
 | 
						|
                    @click="isShowConfirmPassword = !isShowConfirmPassword"
 | 
						|
                  /> </template
 | 
						|
              ></BaseInput>
 | 
						|
            </BaseInputGroup>
 | 
						|
          </BaseInputGrid>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <BaseDivider class="mb-5 md:mb-8" />
 | 
						|
 | 
						|
        <!-- Billing Address   -->
 | 
						|
        <div class="grid grid-cols-5 gap-4 mb-8">
 | 
						|
          <h6 class="col-span-5 text-lg font-semibold text-left lg:col-span-1">
 | 
						|
            {{ $t('customers.billing_address') }}
 | 
						|
          </h6>
 | 
						|
 | 
						|
          <BaseInputGrid
 | 
						|
            v-if="customerStore.currentCustomer.billing"
 | 
						|
            class="col-span-5 lg:col-span-4"
 | 
						|
          >
 | 
						|
            <BaseInputGroup
 | 
						|
              :label="$t('customers.name')"
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model.trim="customerStore.currentCustomer.billing.name"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                type="text"
 | 
						|
                class="w-full"
 | 
						|
                name="address_name"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :label="$t('customers.country')"
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
            >
 | 
						|
              <BaseMultiselect
 | 
						|
                v-model="customerStore.currentCustomer.billing.country_id"
 | 
						|
                value-prop="id"
 | 
						|
                label="name"
 | 
						|
                track-by="name"
 | 
						|
                resolve-on-load
 | 
						|
                searchable
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                :options="globalStore.countries"
 | 
						|
                :placeholder="$t('general.select_country')"
 | 
						|
                class="w-full"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :label="$t('customers.state')"
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model="customerStore.currentCustomer.billing.state"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                name="billing.state"
 | 
						|
                type="text"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
              :label="$t('customers.city')"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model="customerStore.currentCustomer.billing.city"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                name="billing.city"
 | 
						|
                type="text"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :label="$t('customers.address')"
 | 
						|
              :error="
 | 
						|
                (v$.currentCustomer.billing.address_street_1.$error &&
 | 
						|
                  v$.currentCustomer.billing.address_street_1.$errors[0]
 | 
						|
                    .$message) ||
 | 
						|
                (v$.currentCustomer.billing.address_street_2.$error &&
 | 
						|
                  v$.currentCustomer.billing.address_street_2.$errors[0]
 | 
						|
                    .$message)
 | 
						|
              "
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
            >
 | 
						|
              <BaseTextarea
 | 
						|
                v-model.trim="
 | 
						|
                  customerStore.currentCustomer.billing.address_street_1
 | 
						|
                "
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                :placeholder="$t('general.street_1')"
 | 
						|
                type="text"
 | 
						|
                name="billing_street1"
 | 
						|
                :container-class="`mt-3`"
 | 
						|
                @input="v$.currentCustomer.billing.address_street_1.$touch()"
 | 
						|
              />
 | 
						|
 | 
						|
              <BaseTextarea
 | 
						|
                v-model.trim="
 | 
						|
                  customerStore.currentCustomer.billing.address_street_2
 | 
						|
                "
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                :placeholder="$t('general.street_2')"
 | 
						|
                type="text"
 | 
						|
                class="mt-3"
 | 
						|
                name="billing_street2"
 | 
						|
                :container-class="`mt-3`"
 | 
						|
                @input="v$.currentCustomer.billing.address_street_2.$touch()"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <div class="space-y-6">
 | 
						|
              <BaseInputGroup
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                :label="$t('customers.phone')"
 | 
						|
                class="text-left"
 | 
						|
              >
 | 
						|
                <BaseInput
 | 
						|
                  v-model.trim="customerStore.currentCustomer.billing.phone"
 | 
						|
                  :content-loading="isFetchingInitialData"
 | 
						|
                  type="text"
 | 
						|
                  name="phone"
 | 
						|
                />
 | 
						|
              </BaseInputGroup>
 | 
						|
 | 
						|
              <BaseInputGroup
 | 
						|
                :label="$t('customers.zip_code')"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                class="mt-2 text-left"
 | 
						|
              >
 | 
						|
                <BaseInput
 | 
						|
                  v-model.trim="customerStore.currentCustomer.billing.zip"
 | 
						|
                  :content-loading="isFetchingInitialData"
 | 
						|
                  type="text"
 | 
						|
                  name="zip"
 | 
						|
                />
 | 
						|
              </BaseInputGroup>
 | 
						|
            </div>
 | 
						|
          </BaseInputGrid>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <BaseDivider class="mb-5 md:mb-8" />
 | 
						|
 | 
						|
        <!-- Billing Address Copy Button  -->
 | 
						|
        <div
 | 
						|
          class="flex items-center justify-start mb-6 md:justify-end md:mb-0"
 | 
						|
        >
 | 
						|
          <div class="p-1">
 | 
						|
            <BaseButton
 | 
						|
              type="button"
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
              size="sm"
 | 
						|
              variant="primary-outline"
 | 
						|
              @click="customerStore.copyAddress(true)"
 | 
						|
            >
 | 
						|
              <template #left="slotProps">
 | 
						|
                <BaseIcon
 | 
						|
                  name="DocumentDuplicateIcon"
 | 
						|
                  :class="slotProps.class"
 | 
						|
                />
 | 
						|
              </template>
 | 
						|
              {{ $t('customers.copy_billing_address') }}
 | 
						|
            </BaseButton>
 | 
						|
          </div>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <!-- Shipping Address  -->
 | 
						|
        <div
 | 
						|
          v-if="customerStore.currentCustomer.shipping"
 | 
						|
          class="grid grid-cols-5 gap-4 mb-8"
 | 
						|
        >
 | 
						|
          <h6 class="col-span-5 text-lg font-semibold text-left lg:col-span-1">
 | 
						|
            {{ $t('customers.shipping_address') }}
 | 
						|
          </h6>
 | 
						|
 | 
						|
          <BaseInputGrid class="col-span-5 lg:col-span-4">
 | 
						|
            <BaseInputGroup
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
              :label="$t('customers.name')"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model.trim="customerStore.currentCustomer.shipping.name"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                type="text"
 | 
						|
                name="address_name"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :label="$t('customers.country')"
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
            >
 | 
						|
              <BaseMultiselect
 | 
						|
                v-model="customerStore.currentCustomer.shipping.country_id"
 | 
						|
                value-prop="id"
 | 
						|
                label="name"
 | 
						|
                track-by="name"
 | 
						|
                resolve-on-load
 | 
						|
                searchable
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                :options="globalStore.countries"
 | 
						|
                :placeholder="$t('general.select_country')"
 | 
						|
                class="w-full"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :label="$t('customers.state')"
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model="customerStore.currentCustomer.shipping.state"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                name="shipping.state"
 | 
						|
                type="text"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
              :label="$t('customers.city')"
 | 
						|
            >
 | 
						|
              <BaseInput
 | 
						|
                v-model="customerStore.currentCustomer.shipping.city"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                name="shipping.city"
 | 
						|
                type="text"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <BaseInputGroup
 | 
						|
              :label="$t('customers.address')"
 | 
						|
              :content-loading="isFetchingInitialData"
 | 
						|
              :error="
 | 
						|
                (v$.currentCustomer.shipping.address_street_1.$error &&
 | 
						|
                  v$.currentCustomer.shipping.address_street_1.$errors[0]
 | 
						|
                    .$message) ||
 | 
						|
                (v$.currentCustomer.shipping.address_street_2.$error &&
 | 
						|
                  v$.currentCustomer.shipping.address_street_2.$errors[0]
 | 
						|
                    .$message)
 | 
						|
              "
 | 
						|
            >
 | 
						|
              <BaseTextarea
 | 
						|
                v-model.trim="
 | 
						|
                  customerStore.currentCustomer.shipping.address_street_1
 | 
						|
                "
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                type="text"
 | 
						|
                :placeholder="$t('general.street_1')"
 | 
						|
                name="shipping_street1"
 | 
						|
                @input="v$.currentCustomer.shipping.address_street_1.$touch()"
 | 
						|
              />
 | 
						|
 | 
						|
              <BaseTextarea
 | 
						|
                v-model.trim="
 | 
						|
                  customerStore.currentCustomer.shipping.address_street_2
 | 
						|
                "
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                type="text"
 | 
						|
                :placeholder="$t('general.street_2')"
 | 
						|
                name="shipping_street2"
 | 
						|
                class="mt-3"
 | 
						|
                :container-class="`mt-3`"
 | 
						|
                @input="v$.currentCustomer.shipping.address_street_2.$touch()"
 | 
						|
              />
 | 
						|
            </BaseInputGroup>
 | 
						|
 | 
						|
            <div class="space-y-6">
 | 
						|
              <BaseInputGroup
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                :label="$t('customers.phone')"
 | 
						|
                class="text-left"
 | 
						|
              >
 | 
						|
                <BaseInput
 | 
						|
                  v-model.trim="customerStore.currentCustomer.shipping.phone"
 | 
						|
                  :content-loading="isFetchingInitialData"
 | 
						|
                  type="text"
 | 
						|
                  name="phone"
 | 
						|
                />
 | 
						|
              </BaseInputGroup>
 | 
						|
 | 
						|
              <BaseInputGroup
 | 
						|
                :label="$t('customers.zip_code')"
 | 
						|
                :content-loading="isFetchingInitialData"
 | 
						|
                class="mt-2 text-left"
 | 
						|
              >
 | 
						|
                <BaseInput
 | 
						|
                  v-model.trim="customerStore.currentCustomer.shipping.zip"
 | 
						|
                  :content-loading="isFetchingInitialData"
 | 
						|
                  type="text"
 | 
						|
                  name="zip"
 | 
						|
                />
 | 
						|
              </BaseInputGroup>
 | 
						|
            </div>
 | 
						|
          </BaseInputGrid>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <BaseDivider
 | 
						|
          v-if="customFieldStore.customFields.length > 0"
 | 
						|
          class="mb-5 md:mb-8"
 | 
						|
        />
 | 
						|
 | 
						|
        <!-- Customer Custom Fields -->
 | 
						|
        <div class="grid grid-cols-5 gap-2 mb-8">
 | 
						|
          <h6
 | 
						|
            v-if="customFieldStore.customFields.length > 0"
 | 
						|
            class="col-span-5 text-lg font-semibold text-left lg:col-span-1"
 | 
						|
          >
 | 
						|
            {{ $t('settings.custom_fields.title') }}
 | 
						|
          </h6>
 | 
						|
 | 
						|
          <div class="col-span-5 lg:col-span-4">
 | 
						|
            <CustomerCustomFields
 | 
						|
              type="Customer"
 | 
						|
              :store="customerStore"
 | 
						|
              store-prop="currentCustomer"
 | 
						|
              :is-edit="isEdit"
 | 
						|
              :is-loading="isLoadingContent"
 | 
						|
              :custom-field-scope="customFieldValidationScope"
 | 
						|
            />
 | 
						|
          </div>
 | 
						|
        </div>
 | 
						|
      </BaseCard>
 | 
						|
    </form>
 | 
						|
  </BasePage>
 | 
						|
</template>
 | 
						|
 | 
						|
<script setup>
 | 
						|
import { computed, onMounted, ref } from 'vue'
 | 
						|
import { useRoute, useRouter } from 'vue-router'
 | 
						|
import { useI18n } from 'vue-i18n'
 | 
						|
import {
 | 
						|
  required,
 | 
						|
  minLength,
 | 
						|
  url,
 | 
						|
  maxLength,
 | 
						|
  helpers,
 | 
						|
  email,
 | 
						|
  sameAs,
 | 
						|
  requiredIf,
 | 
						|
} from '@vuelidate/validators'
 | 
						|
import useVuelidate from '@vuelidate/core'
 | 
						|
import { useCustomerStore } from '@/scripts/admin/stores/customer'
 | 
						|
import { useCustomFieldStore } from '@/scripts/admin/stores/custom-field'
 | 
						|
import CustomerCustomFields from '@/scripts/admin/components/custom-fields/CreateCustomFields.vue'
 | 
						|
import { useGlobalStore } from '@/scripts/admin/stores/global'
 | 
						|
import CopyInputField from '@/scripts/admin/components/CopyInputField.vue'
 | 
						|
import { useCompanyStore } from '@/scripts/admin/stores/company'
 | 
						|
 | 
						|
const customerStore = useCustomerStore()
 | 
						|
const customFieldStore = useCustomFieldStore()
 | 
						|
const globalStore = useGlobalStore()
 | 
						|
const companyStore = useCompanyStore()
 | 
						|
 | 
						|
const customFieldValidationScope = 'customFields'
 | 
						|
 | 
						|
const { t } = useI18n()
 | 
						|
 | 
						|
const router = useRouter()
 | 
						|
const route = useRoute()
 | 
						|
 | 
						|
let isFetchingInitialData = ref(false)
 | 
						|
let isShowPassword = ref(false)
 | 
						|
let isShowConfirmPassword = ref(false)
 | 
						|
 | 
						|
let active = ref(false)
 | 
						|
const isSaving = ref(false)
 | 
						|
 | 
						|
const isEdit = computed(() => route.name === 'customers.edit')
 | 
						|
 | 
						|
let isLoadingContent = computed(() => customerStore.isFetchingInitialSettings)
 | 
						|
 | 
						|
const pageTitle = computed(() =>
 | 
						|
  isEdit.value ? t('customers.edit_customer') : t('customers.new_customer')
 | 
						|
)
 | 
						|
 | 
						|
const rules = computed(() => {
 | 
						|
  return {
 | 
						|
    currentCustomer: {
 | 
						|
      name: {
 | 
						|
        required: helpers.withMessage(t('validation.required'), required),
 | 
						|
        minLength: helpers.withMessage(
 | 
						|
          t('validation.name_min_length', { count: 3 }),
 | 
						|
          minLength(3)
 | 
						|
        ),
 | 
						|
      },
 | 
						|
      prefix: {
 | 
						|
        minLength: helpers.withMessage(
 | 
						|
          t('validation.name_min_length', { count: 3 }),
 | 
						|
          minLength(3)
 | 
						|
        ),
 | 
						|
      },
 | 
						|
      currency_id: {
 | 
						|
        required: helpers.withMessage(t('validation.required'), required),
 | 
						|
      },
 | 
						|
 | 
						|
      email: {
 | 
						|
        required: helpers.withMessage(
 | 
						|
          t('validation.required'),
 | 
						|
          requiredIf(customerStore.currentCustomer.enable_portal == true)
 | 
						|
        ),
 | 
						|
        email: helpers.withMessage(t('validation.email_incorrect'), email),
 | 
						|
      },
 | 
						|
      password: {
 | 
						|
        required: helpers.withMessage(
 | 
						|
          t('validation.required'),
 | 
						|
          requiredIf(
 | 
						|
            customerStore.currentCustomer.enable_portal == true &&
 | 
						|
              !customerStore.currentCustomer.password_added
 | 
						|
          )
 | 
						|
        ),
 | 
						|
        minLength: helpers.withMessage(
 | 
						|
          t('validation.password_min_length', { count: 8 }),
 | 
						|
          minLength(8)
 | 
						|
        ),
 | 
						|
      },
 | 
						|
      confirm_password: {
 | 
						|
        sameAsPassword: helpers.withMessage(
 | 
						|
          t('validation.password_incorrect'),
 | 
						|
          sameAs(customerStore.currentCustomer.password)
 | 
						|
        ),
 | 
						|
      },
 | 
						|
 | 
						|
      website: {
 | 
						|
        url: helpers.withMessage(t('validation.invalid_url'), url),
 | 
						|
      },
 | 
						|
      billing: {
 | 
						|
        address_street_1: {
 | 
						|
          maxLength: helpers.withMessage(
 | 
						|
            t('validation.address_maxlength', { count: 255 }),
 | 
						|
            maxLength(255)
 | 
						|
          ),
 | 
						|
        },
 | 
						|
 | 
						|
        address_street_2: {
 | 
						|
          maxLength: helpers.withMessage(
 | 
						|
            t('validation.address_maxlength', { count: 255 }),
 | 
						|
            maxLength(255)
 | 
						|
          ),
 | 
						|
        },
 | 
						|
      },
 | 
						|
 | 
						|
      shipping: {
 | 
						|
        address_street_1: {
 | 
						|
          maxLength: helpers.withMessage(
 | 
						|
            t('validation.address_maxlength', { count: 255 }),
 | 
						|
            maxLength(255)
 | 
						|
          ),
 | 
						|
        },
 | 
						|
 | 
						|
        address_street_2: {
 | 
						|
          maxLength: helpers.withMessage(
 | 
						|
            t('validation.address_maxlength', { count: 255 }),
 | 
						|
            maxLength(255)
 | 
						|
          ),
 | 
						|
        },
 | 
						|
      },
 | 
						|
    },
 | 
						|
  }
 | 
						|
})
 | 
						|
 | 
						|
const getCustomerPortalUrl = computed(() => {
 | 
						|
  return `${window.location.origin}/${companyStore.selectedCompany.slug}/customer/login`
 | 
						|
})
 | 
						|
 | 
						|
const v$ = useVuelidate(rules, customerStore, {
 | 
						|
  $scope: customFieldValidationScope,
 | 
						|
})
 | 
						|
 | 
						|
customerStore.resetCurrentCustomer()
 | 
						|
 | 
						|
customerStore.fetchCustomerInitialSettings(isEdit.value)
 | 
						|
 | 
						|
async function submitCustomerData() {
 | 
						|
  v$.value.$touch()
 | 
						|
 | 
						|
  if (v$.value.$invalid) {
 | 
						|
    return true
 | 
						|
  }
 | 
						|
 | 
						|
  isSaving.value = true
 | 
						|
 | 
						|
  let data = {
 | 
						|
    ...customerStore.currentCustomer,
 | 
						|
  }
 | 
						|
 | 
						|
  let response = null
 | 
						|
 | 
						|
  try {
 | 
						|
    const action = isEdit.value
 | 
						|
      ? customerStore.updateCustomer
 | 
						|
      : customerStore.addCustomer
 | 
						|
    response = await action(data)
 | 
						|
  } catch (err) {
 | 
						|
    isSaving.value = false
 | 
						|
    return
 | 
						|
  }
 | 
						|
 | 
						|
  router.push(`/admin/customers/${response.data.data.id}/view`)
 | 
						|
}
 | 
						|
</script>
 |