Files
DriverVault/Web App/web/src/components/CarFormModal.vue
T
tajniak81andClaude Opus 5 f7caeaf907 A date typed in the order you chose, not the browser's
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>
2026-08-22 20:18:18 +02:00

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>