mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-04-15 17:24:10 +00:00
Now that the legacy v1 frontend (commit 064bdf53) is gone, the v2 directory is the only frontend and the v2 suffix is just noise. Renames resources/scripts-v2 to resources/scripts via git mv (so git records the move as renames, preserving blame and log --follow), then bulk-rewrites the 152 files that imported via @v2/... to use @/scripts/... instead. The existing @ alias (resources/) covers the new path with no extra config needed.
Drops the now-unused @v2 alias from vite.config.js and points the laravel-vite-plugin entry at resources/scripts/main.ts. Updates the only blade reference (resources/views/app.blade.php) to match. The package.json test script (eslint ./resources/scripts) automatically targets the right place after the rename without any edit.
Verified: npm run build exits clean and the Vite warning lines now reference resources/scripts/plugins/i18n.ts, confirming every import resolved through the new path. git log --follow on any moved file walks back through its scripts-v2 history.
279 lines
7.6 KiB
Vue
279 lines
7.6 KiB
Vue
<script setup lang="ts">
|
|
import { computed, ref, watch, onMounted } from 'vue'
|
|
import type { Ref } from 'vue'
|
|
|
|
interface CustomFieldOption {
|
|
label: string
|
|
value: string
|
|
}
|
|
|
|
interface CustomFieldData {
|
|
label: string
|
|
value: string
|
|
slug: string
|
|
model_type: string
|
|
}
|
|
|
|
interface FieldGroup {
|
|
label: string
|
|
fields: CustomFieldOption[]
|
|
}
|
|
|
|
type FieldType =
|
|
| 'shipping'
|
|
| 'billing'
|
|
| 'customer'
|
|
| 'invoice'
|
|
| 'estimate'
|
|
| 'payment'
|
|
| 'company'
|
|
|
|
interface Props {
|
|
contentLoading?: boolean
|
|
modelValue?: string
|
|
fields?: FieldType[] | null
|
|
customFields?: CustomFieldData[]
|
|
}
|
|
|
|
interface Emits {
|
|
(e: 'update:modelValue', value: string): void
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
contentLoading: false,
|
|
modelValue: '',
|
|
fields: null,
|
|
customFields: () => [],
|
|
})
|
|
|
|
const emit = defineEmits<Emits>()
|
|
|
|
const fieldList = ref<FieldGroup[]>([])
|
|
const invoiceFields = ref<CustomFieldData[]>([])
|
|
const estimateFields = ref<CustomFieldData[]>([])
|
|
const paymentFields = ref<CustomFieldData[]>([])
|
|
const customerFields = ref<CustomFieldData[]>([])
|
|
|
|
watch(
|
|
() => props.fields,
|
|
() => {
|
|
if (props.fields && props.fields.length > 0) {
|
|
getFields()
|
|
}
|
|
}
|
|
)
|
|
|
|
watch(
|
|
() => props.customFields,
|
|
(newValue: CustomFieldData[] | undefined) => {
|
|
const data = newValue ?? []
|
|
invoiceFields.value = data.filter((field) => field.model_type === 'Invoice')
|
|
customerFields.value = data.filter(
|
|
(field) => field.model_type === 'Customer'
|
|
)
|
|
paymentFields.value = data.filter(
|
|
(field) => field.model_type === 'Payment'
|
|
)
|
|
estimateFields.value = data.filter(
|
|
(field) => field.model_type === 'Estimate'
|
|
)
|
|
getFields()
|
|
}
|
|
)
|
|
|
|
const value = computed<string>({
|
|
get: () => props.modelValue,
|
|
set: (val: string) => {
|
|
emit('update:modelValue', val)
|
|
},
|
|
})
|
|
|
|
function getFields(): void {
|
|
fieldList.value = []
|
|
if (!props.fields || props.fields.length === 0) return
|
|
|
|
if (props.fields.includes('shipping')) {
|
|
fieldList.value.push({
|
|
label: 'Shipping Address',
|
|
fields: [
|
|
{ label: 'Address name', value: 'SHIPPING_ADDRESS_NAME' },
|
|
{ label: 'Country', value: 'SHIPPING_COUNTRY' },
|
|
{ label: 'State', value: 'SHIPPING_STATE' },
|
|
{ label: 'City', value: 'SHIPPING_CITY' },
|
|
{ label: 'Address Street 1', value: 'SHIPPING_ADDRESS_STREET_1' },
|
|
{ label: 'Address Street 2', value: 'SHIPPING_ADDRESS_STREET_2' },
|
|
{ label: 'Phone', value: 'SHIPPING_PHONE' },
|
|
{ label: 'Zip Code', value: 'SHIPPING_ZIP_CODE' },
|
|
],
|
|
})
|
|
}
|
|
|
|
if (props.fields.includes('billing')) {
|
|
fieldList.value.push({
|
|
label: 'Billing Address',
|
|
fields: [
|
|
{ label: 'Address name', value: 'BILLING_ADDRESS_NAME' },
|
|
{ label: 'Country', value: 'BILLING_COUNTRY' },
|
|
{ label: 'State', value: 'BILLING_STATE' },
|
|
{ label: 'City', value: 'BILLING_CITY' },
|
|
{ label: 'Address Street 1', value: 'BILLING_ADDRESS_STREET_1' },
|
|
{ label: 'Address Street 2', value: 'BILLING_ADDRESS_STREET_2' },
|
|
{ label: 'Phone', value: 'BILLING_PHONE' },
|
|
{ label: 'Zip Code', value: 'BILLING_ZIP_CODE' },
|
|
],
|
|
})
|
|
}
|
|
|
|
if (props.fields.includes('customer')) {
|
|
fieldList.value.push({
|
|
label: 'Customer',
|
|
fields: [
|
|
{ label: 'Display Name', value: 'CONTACT_DISPLAY_NAME' },
|
|
{ label: 'Contact Name', value: 'PRIMARY_CONTACT_NAME' },
|
|
{ label: 'Email', value: 'CONTACT_EMAIL' },
|
|
{ label: 'Phone', value: 'CONTACT_PHONE' },
|
|
{ label: 'Website', value: 'CONTACT_WEBSITE' },
|
|
{ label: 'Tax ID', value: 'CONTACT_TAX_ID' },
|
|
...customerFields.value.map((i) => ({
|
|
label: i.label,
|
|
value: i.slug,
|
|
})),
|
|
],
|
|
})
|
|
}
|
|
|
|
if (props.fields.includes('invoice')) {
|
|
fieldList.value.push({
|
|
label: 'Invoice',
|
|
fields: [
|
|
{ label: 'Date', value: 'INVOICE_DATE' },
|
|
{ label: 'Due Date', value: 'INVOICE_DUE_DATE' },
|
|
{ label: 'Number', value: 'INVOICE_NUMBER' },
|
|
{ label: 'Ref Number', value: 'INVOICE_REF_NUMBER' },
|
|
...invoiceFields.value.map((i) => ({
|
|
label: i.label,
|
|
value: i.slug,
|
|
})),
|
|
],
|
|
})
|
|
}
|
|
|
|
if (props.fields.includes('estimate')) {
|
|
fieldList.value.push({
|
|
label: 'Estimate',
|
|
fields: [
|
|
{ label: 'Date', value: 'ESTIMATE_DATE' },
|
|
{ label: 'Expiry Date', value: 'ESTIMATE_EXPIRY_DATE' },
|
|
{ label: 'Number', value: 'ESTIMATE_NUMBER' },
|
|
{ label: 'Ref Number', value: 'ESTIMATE_REF_NUMBER' },
|
|
...estimateFields.value.map((i) => ({
|
|
label: i.label,
|
|
value: i.slug,
|
|
})),
|
|
],
|
|
})
|
|
}
|
|
|
|
if (props.fields.includes('payment')) {
|
|
fieldList.value.push({
|
|
label: 'Payment',
|
|
fields: [
|
|
{ label: 'Date', value: 'PAYMENT_DATE' },
|
|
{ label: 'Number', value: 'PAYMENT_NUMBER' },
|
|
{ label: 'Mode', value: 'PAYMENT_MODE' },
|
|
{ label: 'Amount', value: 'PAYMENT_AMOUNT' },
|
|
...paymentFields.value.map((i) => ({
|
|
label: i.label,
|
|
value: i.slug,
|
|
})),
|
|
],
|
|
})
|
|
}
|
|
|
|
if (props.fields.includes('company')) {
|
|
fieldList.value.push({
|
|
label: 'Company',
|
|
fields: [
|
|
{ label: 'Company Name', value: 'COMPANY_NAME' },
|
|
{ label: 'Country', value: 'COMPANY_COUNTRY' },
|
|
{ label: 'State', value: 'COMPANY_STATE' },
|
|
{ label: 'City', value: 'COMPANY_CITY' },
|
|
{ label: 'Address Street 1', value: 'COMPANY_ADDRESS_STREET_1' },
|
|
{ label: 'Address Street 2', value: 'COMPANY_ADDRESS_STREET_2' },
|
|
{ label: 'Phone', value: 'COMPANY_PHONE' },
|
|
{ label: 'Zip Code', value: 'COMPANY_ZIP_CODE' },
|
|
{ label: 'Vat Id', value: 'COMPANY_VAT' },
|
|
{ label: 'Tax Id', value: 'COMPANY_TAX' },
|
|
],
|
|
})
|
|
}
|
|
}
|
|
|
|
getFields()
|
|
</script>
|
|
|
|
<template>
|
|
<BaseContentPlaceholders v-if="contentLoading">
|
|
<BaseContentPlaceholdersBox
|
|
:rounded="true"
|
|
class="w-full"
|
|
style="height: 200px"
|
|
/>
|
|
</BaseContentPlaceholders>
|
|
|
|
<div v-else class="relative">
|
|
<div class="absolute bottom-0 right-0 z-10">
|
|
<BaseDropdown
|
|
:close-on-select="true"
|
|
max-height="220"
|
|
position="top-end"
|
|
width-class="w-auto min-w-[40rem]"
|
|
class="mb-2"
|
|
>
|
|
<template #activator>
|
|
<BaseButton type="button" variant="primary-outline" class="mr-4">
|
|
{{ $t('settings.customization.insert_fields') }}
|
|
<template #left="slotProps">
|
|
<BaseIcon name="PlusSmIcon" :class="slotProps.class" />
|
|
</template>
|
|
</BaseButton>
|
|
</template>
|
|
|
|
<div class="flex p-2">
|
|
<ul v-for="(type, index) in fieldList" :key="index" class="list-none">
|
|
<li class="mb-1 ml-2 text-xs font-semibold text-muted uppercase">
|
|
{{ type.label }}
|
|
</li>
|
|
|
|
<li
|
|
v-for="(field, fieldIndex) in type.fields"
|
|
:key="fieldIndex"
|
|
class="
|
|
w-48
|
|
text-sm
|
|
font-normal
|
|
cursor-pointer
|
|
hover:bg-hover-strong
|
|
rounded
|
|
ml-1
|
|
py-0.5
|
|
"
|
|
@click="value += `{${field.value}}`"
|
|
>
|
|
<div class="flex pl-1">
|
|
<BaseIcon
|
|
name="ChevronDoubleRightIcon"
|
|
class="h-3 mt-1 mr-2 text-subtle"
|
|
/>
|
|
|
|
{{ field.label }}
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</BaseDropdown>
|
|
</div>
|
|
<BaseEditor v-model="value" />
|
|
</div>
|
|
</template>
|