jcloude/dashboard/src/components/billing/NewAddressForm.vue
2025-12-23 20:48:07 +08:00

249 lines
5.1 KiB
Vue

<template>
<div>
<div class="flex flex-col gap-5">
<div
v-for="section in sections"
:key="section.name"
class="grid gap-4"
:class="'grid-cols-' + section.columns"
>
<div v-for="field in section.fields" :key="field.name">
<FormControl
v-model="billingInformation[field.fieldname]"
:label="field.label || field.fieldname"
:type="getInputType(field)"
:name="field.fieldname"
:options="field.options"
:disabled="props.disableForm"
:required="field.required"
/>
</div>
</div>
<div v-show="billingInformation.country == 'India'">
<FormControl
label="I have GSTIN"
type="checkbox"
:disabled="props.disableForm"
v-model="gstApplicable"
/>
<FormControl
v-if="gstApplicable"
class="mt-5"
label="GSTIN"
type="text"
:disabled="props.disableForm"
v-model="billingInformation.gstin"
/>
</div>
</div>
<ErrorMessage class="mt-2" :message="updateBillingInformation.error" />
</div>
</template>
<script setup>
import { FormControl, ErrorMessage, createResource } from 'jingrow-ui';
import { ref, computed, inject, watch } from 'vue';
import { toast } from 'vue-sonner';
import { DashboardError } from '../../utils/error';
const emit = defineEmits(['success']);
const team = inject('team');
const billingInformation = defineModel();
const props = defineProps({
disableForm: { type: Boolean, default: false },
});
const updateBillingInformation = createResource({
url: 'jcloude.api.account.update_billing_information',
makeParams: () => {
return { billing_details: billingInformation.value };
},
validate: async () => {
let error = await validate();
if (error) throw new DashboardError(error);
},
onSuccess: () => {
toast.success('Billing information updated');
emit('success');
},
});
const gstApplicable = ref(false);
watch(
() => billingInformation.value.gstin,
(gstin) => {
gstApplicable.value = gstin && gstin !== 'Not Applicable';
},
);
async function validate() {
// validate mandatory fields
for (let field of sections.value.flatMap((s) => s.fields)) {
if (field.required && !billingInformation.value[field.fieldname]) {
return `${field.label} is required`;
}
}
if (!gstApplicable.value) {
billingInformation.value.gstin = 'Not Applicable';
}
// validate gstin
return await validateGST();
}
const _indianStates = [
'Andaman and Nicobar Islands',
'Andhra Pradesh',
'Arunachal Pradesh',
'Assam',
'Bihar',
'Chandigarh',
'Chhattisgarh',
'Dadra and Nagar Haveli and Daman and Diu',
'Delhi',
'Goa',
'Gujarat',
'Haryana',
'Himachal Pradesh',
'Jammu and Kashmir',
'Jharkhand',
'Karnataka',
'Kerala',
'Ladakh',
'Lakshadweep Islands',
'Madhya Pradesh',
'Maharashtra',
'Manipur',
'Meghalaya',
'Mizoram',
'Nagaland',
'Odisha',
'Other Territory',
'Puducherry',
'Punjab',
'Rajasthan',
'Sikkim',
'Tamil Nadu',
'Telangana',
'Tripura',
'Uttar Pradesh',
'Uttarakhand',
'West Bengal',
];
const _countryList = createResource({
url: 'jcloude.api.account.country_list',
cache: 'countryList',
auto: true,
onSuccess: () => {
let userCountry = team.pg?.country;
if (userCountry) {
let country = countryList.value?.find((d) => d.label === userCountry);
if (country) {
billingInformation.value.country = country.value;
}
}
},
});
const countryList = computed(() => {
return (_countryList.data || []).map((d) => ({
label: d.name,
value: d.name,
}));
});
const indianStates = computed(() => {
return _indianStates.map((state) => ({
label: state,
value: state,
}));
});
const sections = computed(() => {
return [
{
name: 'Country and City',
columns: 2,
fields: [
{
fieldtype: 'Select',
label: 'Country',
fieldname: 'country',
options: countryList.value,
required: true,
},
{
fieldtype: 'Data',
label: 'City',
fieldname: 'city',
required: true,
},
],
},
{
name: 'Address',
columns: 1,
fields: [
{
fieldtype: 'Data',
label: 'Address',
fieldname: 'address',
required: true,
},
],
},
{
name: 'State and Postal Code',
columns: 2,
fields: [
{
fieldtype:
billingInformation.value.country === 'India' ? 'Select' : 'Data',
label: 'State / Province / Region',
fieldname: 'state',
required: true,
options:
billingInformation.value.country === 'India'
? indianStates.value
: null,
},
{
fieldtype: 'Data',
label: 'Postal Code',
fieldname: 'postal_code',
required: true,
},
],
},
];
});
function getInputType(field) {
return {
Data: 'text',
Int: 'number',
Select: 'select',
Check: 'checkbox',
Password: 'password',
Text: 'textarea',
Date: 'date',
}[field.fieldtype || 'Data'];
}
const _validateGST = createResource({
url: 'jcloude.api.billing.validate_gst',
params: { address: billingInformation.value },
});
async function validateGST() {
billingInformation.value.gstin =
billingInformation.value.gstin || 'Not Applicable';
await _validateGST.submit();
}
defineExpose({ updateBillingInformation, validate });
</script>