Settings › Date format steered every date the app printed, but not one it asked for: `<input type="date">` renders in the browser's own locale and no page setting can move it, so DD-MM-YYYY tables sat above 08/22/2026 boxes. DateField takes over the typing half — a masked box whose segment order comes from the same prefs.dateFormat lib/format.js reads — and leaves the picking half to the browser, behind a calendar button. The value in and out stays ISO, so no caller changed. Native validation now also catches a full-but-impossible date; the old input let a half-typed one through as no date at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
187 lines
8.1 KiB
Vue
187 lines
8.1 KiB
Vue
<script setup>
|
|
import { ref } from "vue";
|
|
import { api } from "../api";
|
|
import { t } from "../i18n";
|
|
import DateField from "./DateField.vue";
|
|
import Modal from "./Modal.vue";
|
|
import PartialDateField from "./PartialDateField.vue";
|
|
|
|
const props = defineProps({ car: { type: Object, default: null } });
|
|
const emit = defineEmits(["saved", "close"]);
|
|
|
|
const isEdit = !!props.car;
|
|
const saving = ref(false);
|
|
const error = ref("");
|
|
const form = ref({
|
|
name: props.car?.name ?? "",
|
|
make: props.car?.make ?? "",
|
|
model: props.car?.model ?? "",
|
|
year: props.car?.year || "",
|
|
registration: props.car?.registration ?? "",
|
|
registrationCountry: props.car?.registrationCountry ?? "",
|
|
vin: props.car?.vin ?? "",
|
|
fuelType: props.car?.fuelType ?? "",
|
|
buildDate: props.car?.buildDate ?? "",
|
|
firstRegistrationDate: props.car?.firstRegistrationDate ?? "",
|
|
oilSpec: props.car?.oilSpec ?? "",
|
|
transmissionOilSpec: props.car?.transmissionOilSpec ?? "",
|
|
differentialOilSpec: props.car?.differentialOilSpec ?? "",
|
|
brakeFluidSpec: props.car?.brakeFluidSpec ?? "",
|
|
coolantSpec: props.car?.coolantSpec ?? "",
|
|
serviceIntervalDays: props.car?.serviceIntervalDays || 365,
|
|
serviceIntervalKm: props.car?.serviceIntervalKm || 15000,
|
|
technicalCheckIntervalDays: props.car?.technicalCheckIntervalDays || 365,
|
|
currentKm: props.car?.currentKm ?? "",
|
|
});
|
|
|
|
async function submit() {
|
|
saving.value = true;
|
|
error.value = "";
|
|
try {
|
|
const payload = {
|
|
name: form.value.name.trim(),
|
|
make: form.value.make.trim(),
|
|
model: form.value.model.trim(),
|
|
year: form.value.year ? Number(form.value.year) : 0,
|
|
registration: form.value.registration.trim(),
|
|
registrationCountry: form.value.registrationCountry.trim(),
|
|
vin: form.value.vin.trim(),
|
|
fuelType: form.value.fuelType,
|
|
buildDate: form.value.buildDate,
|
|
firstRegistrationDate: form.value.firstRegistrationDate,
|
|
oilSpec: form.value.oilSpec.trim(),
|
|
transmissionOilSpec: form.value.transmissionOilSpec.trim(),
|
|
differentialOilSpec: form.value.differentialOilSpec.trim(),
|
|
brakeFluidSpec: form.value.brakeFluidSpec.trim(),
|
|
coolantSpec: form.value.coolantSpec.trim(),
|
|
serviceIntervalDays: Number(form.value.serviceIntervalDays) || 365,
|
|
serviceIntervalKm: Number(form.value.serviceIntervalKm) || 15000,
|
|
technicalCheckIntervalDays: Number(form.value.technicalCheckIntervalDays) || 365,
|
|
currentKm: form.value.currentKm === "" ? 0 : Number(form.value.currentKm),
|
|
};
|
|
const saved = isEdit
|
|
? await api.updateCar(props.car.id, payload)
|
|
: await api.createCar(payload);
|
|
emit("saved", saved);
|
|
} catch (e) {
|
|
error.value = e.message;
|
|
} finally {
|
|
saving.value = false;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Modal :title="isEdit ? t('forms.car.editTitle') : t('forms.car.addTitle')" @close="emit('close')">
|
|
<p v-if="error" class="mb-3 rounded-control bg-danger-soft px-3 py-2 text-sm font-medium text-danger">{{ error }}</p>
|
|
<form class="space-y-3" @submit.prevent="submit">
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.name") }}</label>
|
|
<input v-model="form.name" required placeholder="Toyota Yaris" class="dh-input" />
|
|
</div>
|
|
<div class="grid grid-cols-3 gap-2">
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.make") }}</label>
|
|
<input v-model="form.make" placeholder="Toyota" class="dh-input" />
|
|
</div>
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.model") }}</label>
|
|
<input v-model="form.model" placeholder="Yaris" class="dh-input" />
|
|
</div>
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.year") }}</label>
|
|
<input v-model="form.year" type="number" placeholder="2015" class="dh-input data" />
|
|
</div>
|
|
</div>
|
|
<div class="grid grid-cols-3 gap-2">
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.registration") }}</label>
|
|
<input v-model="form.registration" placeholder="ABC 1234" class="dh-input" />
|
|
</div>
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.registrationCountry") }}</label>
|
|
<input v-model="form.registrationCountry" :placeholder="t('forms.car.registrationCountryPlaceholder')" class="dh-input" />
|
|
</div>
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.vin") }}</label>
|
|
<input v-model="form.vin" :placeholder="t('forms.car.vinPlaceholder')" maxlength="17" class="dh-input data uppercase" />
|
|
</div>
|
|
</div>
|
|
<div class="grid grid-cols-3 gap-2">
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.fuelType") }}</label>
|
|
<select v-model="form.fuelType" class="dh-input">
|
|
<option value="">{{ t("common.empty") }}</option>
|
|
<option value="petrol">{{ t("enums.fuelType.petrol") }}</option>
|
|
<option value="petrol_lpg">{{ t("enums.fuelType.petrol_lpg") }}</option>
|
|
<option value="diesel">{{ t("enums.fuelType.diesel") }}</option>
|
|
<option value="diesel_lpg">{{ t("enums.fuelType.diesel_lpg") }}</option>
|
|
<option value="hybrid">{{ t("enums.fuelType.hybrid") }}</option>
|
|
<option value="electric">{{ t("enums.fuelType.electric") }}</option>
|
|
<option value="hydrogen">{{ t("enums.fuelType.hydrogen") }}</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.buildDate") }}</label>
|
|
<PartialDateField v-model="form.buildDate" />
|
|
</div>
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.firstRegistration") }}</label>
|
|
<DateField v-model="form.firstRegistrationDate" />
|
|
</div>
|
|
</div>
|
|
<div class="grid grid-cols-2 gap-2">
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.oilSpec") }}</label>
|
|
<input v-model="form.oilSpec" placeholder="0W20" class="dh-input" />
|
|
</div>
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.currentKm") }}</label>
|
|
<input v-model="form.currentKm" type="number" placeholder="270185" class="dh-input data" />
|
|
</div>
|
|
</div>
|
|
<div class="grid grid-cols-2 gap-2">
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.transmissionOilSpec") }}</label>
|
|
<input v-model="form.transmissionOilSpec" placeholder="Toyota WS" class="dh-input" />
|
|
</div>
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.differentialOilSpec") }}</label>
|
|
<input v-model="form.differentialOilSpec" placeholder="SAE 75W-90 GL-5" class="dh-input" />
|
|
</div>
|
|
</div>
|
|
<div class="grid grid-cols-2 gap-2">
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.brakeFluidSpec") }}</label>
|
|
<input v-model="form.brakeFluidSpec" placeholder="DOT 4" class="dh-input" />
|
|
</div>
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.coolantSpec") }}</label>
|
|
<input v-model="form.coolantSpec" placeholder="Toyota Super Long Life Coolant" class="dh-input" />
|
|
</div>
|
|
</div>
|
|
<div class="grid grid-cols-2 gap-2">
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.serviceIntervalDays") }}</label>
|
|
<input v-model="form.serviceIntervalDays" type="number" class="dh-input data" />
|
|
</div>
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.serviceIntervalKm") }}</label>
|
|
<input v-model="form.serviceIntervalKm" type="number" class="dh-input data" />
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="dh-label">{{ t("forms.car.technicalCheckIntervalDays") }}</label>
|
|
<input v-model="form.technicalCheckIntervalDays" type="number" class="dh-input data" />
|
|
<p class="mt-1 text-xs text-muted">{{ t("forms.car.technicalCheckHint") }}</p>
|
|
</div>
|
|
<div class="mt-4 flex justify-end gap-2">
|
|
<button type="button" class="dh-btn dh-btn-ghost" @click="emit('close')">{{ t("common.cancel") }}</button>
|
|
<button type="submit" :disabled="saving" class="dh-btn dh-btn-primary">
|
|
{{ saving ? t("common.saving") : isEdit ? t("common.saveChanges") : t("forms.car.submit") }}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</Modal>
|
|
</template>
|