Files
InvoiceShelf/resources/scripts/features/company/customers/store.ts
Darko Gjorgjijoski 71388ec6a5 Rename resources/scripts-v2 to resources/scripts and drop @v2 alias
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.
2026-04-07 12:50:16 +02:00

336 lines
9.0 KiB
TypeScript

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useRoute } from 'vue-router'
import { customerService } from '../../../api/services/customer.service'
import type {
CustomerListParams,
CustomerListResponse,
CustomerStatsParams,
CustomerStatsResponse,
} from '../../../api/services/customer.service'
import { useNotificationStore } from '../../../stores/notification.store'
import { useGlobalStore } from '../../../stores/global.store'
import { useCompanyStore } from '../../../stores/company.store'
import { handleApiError } from '../../../utils/error-handling'
import type { Customer, CreateCustomerPayload } from '../../../types/domain/customer'
import type { Address } from '../../../types/domain/user'
import type { ApiResponse, DeletePayload } from '../../../types/api'
export interface CustomerFormAddress {
name: string | null
phone: string | null
address_street_1: string | null
address_street_2: string | null
city: string | null
state: string | null
country_id: number | null
zip: string | null
type: string | null
}
export interface CustomerForm {
id?: number
name: string
contact_name: string
email: string
phone: string | null
password: string
confirm_password: string
currency_id: number | null
website: string | null
prefix?: string | null
tax_id?: string | null
billing: CustomerFormAddress
shipping: CustomerFormAddress
customFields: unknown[]
fields: unknown[]
enable_portal: boolean
password_added?: boolean
}
export type CustomerViewData = Partial<Customer>
function createAddressStub(): CustomerFormAddress {
return {
name: null,
phone: null,
address_street_1: null,
address_street_2: null,
city: null,
state: null,
country_id: null,
zip: null,
type: null,
}
}
function createCustomerStub(): CustomerForm {
return {
name: '',
contact_name: '',
email: '',
phone: null,
password: '',
confirm_password: '',
currency_id: null,
website: null,
billing: createAddressStub(),
shipping: createAddressStub(),
customFields: [],
fields: [],
enable_portal: false,
}
}
export const useCustomerStore = defineStore('customer', () => {
// State
const customers = ref<Customer[]>([])
const totalCustomers = ref<number>(0)
const selectAllField = ref<boolean>(false)
const selectedCustomers = ref<number[]>([])
const selectedViewCustomer = ref<CustomerViewData>({})
const isFetchingInitialSettings = ref<boolean>(false)
const isFetchingViewData = ref<boolean>(false)
const currentCustomer = ref<CustomerForm>(createCustomerStub())
const editCustomer = ref<Customer | null>(null)
// Getters
const isEdit = computed<boolean>(() => !!currentCustomer.value.id)
// Actions
function resetCurrentCustomer(): void {
currentCustomer.value = createCustomerStub()
}
function copyAddress(fromBillingToShipping = true): void {
if (fromBillingToShipping) {
currentCustomer.value.shipping = {
...currentCustomer.value.billing,
type: 'shipping',
}
}
}
async function fetchCustomerInitialSettings(isEditMode: boolean): Promise<void> {
const route = useRoute()
const globalStore = useGlobalStore()
const companyStore = useCompanyStore()
isFetchingInitialSettings.value = true
const editActions: Promise<unknown>[] = []
if (isEditMode) {
editActions.push(fetchCustomer(Number(route.params.id)))
} else {
currentCustomer.value.currency_id =
companyStore.selectedCompanyCurrency?.id ?? null
}
try {
await Promise.all([
globalStore.fetchCurrencies(),
globalStore.fetchCountries(),
...editActions,
])
isFetchingInitialSettings.value = false
} catch (err: unknown) {
isFetchingInitialSettings.value = false
handleApiError(err)
}
}
async function fetchCustomers(params?: CustomerListParams): Promise<CustomerListResponse> {
try {
const response = await customerService.list(params)
customers.value = response.data
totalCustomers.value = response.meta.customer_total_count
return response
} catch (err: unknown) {
handleApiError(err)
throw err
}
}
async function fetchViewCustomer(
params: { id: number } & CustomerStatsParams
): Promise<CustomerStatsResponse> {
isFetchingViewData.value = true
try {
const { id, ...queryParams } = params
const response = await customerService.getStats(id, queryParams)
selectedViewCustomer.value = {}
Object.assign(selectedViewCustomer.value, response.data)
isFetchingViewData.value = false
return response
} catch (err: unknown) {
isFetchingViewData.value = false
handleApiError(err)
throw err
}
}
async function fetchCustomer(id: number): Promise<ApiResponse<Customer>> {
try {
const response = await customerService.get(id)
Object.assign(currentCustomer.value, response.data)
setAddressStub(response.data as unknown as Record<string, unknown>)
return response
} catch (err: unknown) {
handleApiError(err)
throw err
}
}
async function addCustomer(data: CustomerForm): Promise<ApiResponse<Customer>> {
try {
const response = await customerService.create(data as unknown as CreateCustomerPayload)
customers.value.push(response.data)
const notificationStore = useNotificationStore()
notificationStore.showNotification({
type: 'success',
message: 'customers.created_message',
})
return response
} catch (err: unknown) {
handleApiError(err)
throw err
}
}
async function updateCustomer(data: CustomerForm): Promise<ApiResponse<Customer>> {
try {
const response = await customerService.update(
data.id!,
data as unknown as Partial<CreateCustomerPayload>
)
if (response.data) {
const pos = customers.value.findIndex(
(customer) => customer.id === response.data.id
)
if (pos !== -1) {
customers.value[pos] = response.data
}
const notificationStore = useNotificationStore()
notificationStore.showNotification({
type: 'success',
message: 'customers.updated_message',
})
}
return response
} catch (err: unknown) {
handleApiError(err)
throw err
}
}
async function deleteCustomer(payload: DeletePayload): Promise<{ success: boolean }> {
try {
const response = await customerService.delete(payload)
const index = customers.value.findIndex(
(customer) => customer.id === payload.ids[0]
)
if (index !== -1) {
customers.value.splice(index, 1)
}
const notificationStore = useNotificationStore()
notificationStore.showNotification({
type: 'success',
message: 'customers.deleted_message',
})
return response
} catch (err: unknown) {
handleApiError(err)
throw err
}
}
async function deleteMultipleCustomers(): Promise<{ success: boolean }> {
try {
const response = await customerService.delete({ ids: selectedCustomers.value })
selectedCustomers.value.forEach((customerId) => {
const index = customers.value.findIndex(
(_customer) => _customer.id === customerId
)
if (index !== -1) {
customers.value.splice(index, 1)
}
})
const notificationStore = useNotificationStore()
notificationStore.showNotification({
type: 'success',
message: 'customers.deleted_message',
})
return response
} catch (err: unknown) {
handleApiError(err)
throw err
}
}
function setSelectAllState(data: boolean): void {
selectAllField.value = data
}
function selectCustomer(data: number[]): void {
selectedCustomers.value = data
selectAllField.value = selectedCustomers.value.length === customers.value.length
}
function selectAllCustomers(): void {
if (selectedCustomers.value.length === customers.value.length) {
selectedCustomers.value = []
selectAllField.value = false
} else {
selectedCustomers.value = customers.value.map((customer) => customer.id)
selectAllField.value = true
}
}
function setAddressStub(data: Record<string, unknown>): void {
if (!data.billing) {
currentCustomer.value.billing = createAddressStub()
}
if (!data.shipping) {
currentCustomer.value.shipping = createAddressStub()
}
}
return {
customers,
totalCustomers,
selectAllField,
selectedCustomers,
selectedViewCustomer,
isFetchingInitialSettings,
isFetchingViewData,
currentCustomer,
editCustomer,
isEdit,
resetCurrentCustomer,
copyAddress,
fetchCustomerInitialSettings,
fetchCustomers,
fetchViewCustomer,
fetchCustomer,
addCustomer,
updateCustomer,
deleteCustomer,
deleteMultipleCustomers,
setSelectAllState,
selectCustomer,
selectAllCustomers,
setAddressStub,
}
})