198 lines
7.0 KiB
Vue
198 lines
7.0 KiB
Vue
<template>
|
|
<form @submit.prevent="validate">
|
|
<div class="flex items-center justify-between">
|
|
<h1 class="text-3xl font-bold uppercase">
|
|
{{ customerId ? "Modifications du client" : "Ajout d'un client" }}
|
|
</h1>
|
|
|
|
<UiButton
|
|
class="inline-flex items-center justify-center text-xl text-white uppercase bg-primary-500 h-[50px] px-8 rounded hover:opacity-80 gap-2"
|
|
type="submit"
|
|
:disabled="isLoading || !auth.isAdmin"
|
|
>
|
|
<Icon :name="customerId ? '' : 'mdi:plus'" size="28" />
|
|
{{ customerId ? "Valider" : "Ajouter" }}
|
|
</UiButton>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 gap-y-8 gap-x-80 mb-10 py-12">
|
|
<UiTextInput id="customer-name" v-model="form.name" label="Nom du client" :disabled="!auth.isAdmin"/>
|
|
<UiTextInput id="customer-phone" v-model="form.phone" label="Téléphone" :disabled="!auth.isAdmin"/>
|
|
<UiTextInput id="customer-email" v-model="form.email" label="Email" :disabled="!auth.isAdmin"/>
|
|
</div>
|
|
|
|
<div class="mx-24 mb-4 py-6 border-t border-black"></div>
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h2 class="text-3xl font-bold uppercase">Adresses client</h2>
|
|
<UiButton
|
|
type="button"
|
|
class="inline-flex items-center justify-center text-xl text-white uppercase bg-primary-500 h-[50px] px-8 rounded hover:opacity-80 gap-2"
|
|
:disabled="customerId === null || !auth.isAdmin"
|
|
@click="goToAddAddress"
|
|
>
|
|
<Icon name="mdi:plus" size="28" />
|
|
Ajouter
|
|
</UiButton>
|
|
</div>
|
|
<div class="overflow-x-auto mb-10">
|
|
<table class="w-full border-collapse">
|
|
<thead>
|
|
<tr class="text-left border-b border-gray-200">
|
|
<th class="py-3 pr-4 text-sm uppercase">Libellé</th>
|
|
<th class="py-3 pr-4 text-sm uppercase">Rue</th>
|
|
<th class="py-3 pr-4 text-sm uppercase">Complément</th>
|
|
<th class="py-3 pr-4 text-sm uppercase">Code postal</th>
|
|
<th class="py-3 pr-4 text-sm uppercase">Ville</th>
|
|
<th class="py-3 pr-4 text-sm uppercase">Pays</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<template v-if="form.addresses.length === 0">
|
|
<tr>
|
|
<td colspan="6" class="py-4 text-slate-400">
|
|
Aucune adresse.
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
<template v-else>
|
|
<tr
|
|
v-for="(address, index) in form.addresses"
|
|
:key="address.id ?? index"
|
|
class="border-b border-gray-100 hover:bg-slate-50"
|
|
:class="auth.isAdmin ? 'cursor-pointer' : 'cursor-not-allowed opacity-60'"
|
|
@click="goToEditAddress(address.id ?? null)"
|
|
>
|
|
<td class="py-3 pr-4">{{ address.label || "—" }}</td>
|
|
<td class="py-3 pr-4">{{ address.street || "—" }}</td>
|
|
<td class="py-3 pr-4">{{ address.street2 || "—" }}</td>
|
|
<td class="py-3 pr-4">{{ address.postalCode || "—" }}</td>
|
|
<td class="py-3 pr-4">{{ address.city || "—" }}</td>
|
|
<td class="py-3 pr-4">{{ address.countryCode || "—" }}</td>
|
|
</tr>
|
|
</template>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</form>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import {computed, reactive, ref, watch} from "vue"
|
|
import {createCustomer, getCustomer, updateCustomer} from "~/services/customer"
|
|
import type {CustomerData, CustomerFormData, CustomerPayload} from "~/services/dto/customer-data"
|
|
import {useAuthStore} from "~/stores/auth"
|
|
|
|
const route = useRoute()
|
|
const router = useRouter()
|
|
const auth = useAuthStore()
|
|
|
|
const resolveId = (param: unknown) => {
|
|
const idStr = Array.isArray(param) ? param[0] : param
|
|
if (!idStr) return null
|
|
const id = Number(idStr)
|
|
return Number.isFinite(id) ? id : null
|
|
}
|
|
const customerId = computed(() => resolveId(route.params.id))
|
|
const isLoading = ref(false)
|
|
const form = reactive<CustomerFormData>({
|
|
name: "",
|
|
phone: "",
|
|
email: "",
|
|
addresses: [],
|
|
})
|
|
|
|
const goToAddAddress = () => {
|
|
if (customerId.value === null || !auth.isAdmin) return
|
|
router.push({
|
|
path: "/admin/customer/address",
|
|
query: {
|
|
customerId: String(customerId.value),
|
|
},
|
|
})
|
|
}
|
|
|
|
const goToEditAddress = (addressId: number | null) => {
|
|
if (customerId.value === null || addressId === null || !auth.isAdmin) return
|
|
router.push({
|
|
path: "/admin/customer/address",
|
|
query: {
|
|
customerId: String(customerId.value),
|
|
addressId: String(addressId),
|
|
},
|
|
})
|
|
}
|
|
|
|
const hydrateFromCustomer = (customer: CustomerData | null) => {
|
|
if (!customer) return
|
|
form.name = customer.name ?? ""
|
|
form.phone = customer.phone ?? ""
|
|
form.email = customer.email ?? ""
|
|
if (!Array.isArray(customer.addresses) || customer.addresses.length === 0) {
|
|
form.addresses = []
|
|
return
|
|
}
|
|
if (typeof customer.addresses[0] === "string") {
|
|
form.addresses = []
|
|
return
|
|
}
|
|
|
|
form.addresses = customer.addresses.map((address) => ({
|
|
id: address.id ?? null,
|
|
label: address.label ?? "",
|
|
street: address.street ?? "",
|
|
street2: address.street2 ?? null,
|
|
postalCode: address.postalCode ?? "",
|
|
city: address.city ?? "",
|
|
countryCode: address.countryCode ?? "",
|
|
}))
|
|
}
|
|
|
|
watch(
|
|
() => customerId.value,
|
|
async (id) => {
|
|
if (id === null) return
|
|
isLoading.value = true
|
|
try {
|
|
const customer = await getCustomer(id)
|
|
hydrateFromCustomer(customer)
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
},
|
|
{immediate: true}
|
|
)
|
|
|
|
async function validate() {
|
|
if (isLoading.value) return
|
|
if (!auth.isAdmin) return
|
|
isLoading.value = true
|
|
|
|
try {
|
|
const name = form.name.trim()
|
|
const phone = form.phone?.trim() || null
|
|
const email = form.email?.trim() || null
|
|
|
|
const customerPayload: CustomerPayload = {
|
|
name,
|
|
phone,
|
|
email,
|
|
}
|
|
let targetId: number | null = null
|
|
|
|
if (customerId.value !== null) {
|
|
await updateCustomer(customerId.value, customerPayload)
|
|
targetId = customerId.value
|
|
} else {
|
|
const created = await createCustomer(customerPayload)
|
|
targetId = created.id
|
|
}
|
|
|
|
if (targetId !== null) {
|
|
await router.push(`/admin/customer/${targetId}`)
|
|
}
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
}
|
|
</script>
|