vbv/client/src/components/personalProfile/ProfileEdit.vue

387 lines
15 KiB
Vue

<script setup lang="ts">
import { useEntities } from "@/services/entities";
import AvatarImage from "@/components/ui/AvatarImage.vue";
import { ref } from "vue";
import { type User, useUserStore } from "@/stores/user";
const emit = defineEmits(["cancel", "save"]);
const user = useUserStore();
const { countries, organisations } = useEntities();
const avatarLoading = ref(false);
const error = ref(false);
const formData = ref({
first_name: user.first_name,
last_name: user.last_name,
email: user.email,
street: user.street,
street_number: user.street_number,
postal_code: user.postal_code,
city: user.city,
country_id: user.country?.id,
organisation: user.organisation,
organisation_street: user.organisation_street,
organisation_street_number: user.organisation_street_number,
organisation_postal_code: user.organisation_postal_code,
organisation_city: user.organisation_city,
organisation_country_id: user.organisation_country?.id,
invoice_address: user.invoice_address,
});
async function save() {
const { country_id, organisation_country_id, ...profileData } = formData.value;
const typedProfileData: Partial<User> = { ...profileData };
typedProfileData.country = countries.value.find((c) => c.id === country_id);
typedProfileData.organisation_country = countries.value.find(
(c) => c.id === organisation_country_id
);
await user.updateUserProfile(typedProfileData);
emit("save");
}
async function avatarUpload(e: Event) {
const { files } = e.target as HTMLInputElement;
if (!files?.length) return;
avatarLoading.value = true;
error.value = false;
try {
await user.setUserAvatar(files[0]);
emit("save");
} catch (e) {
error.value = true;
} finally {
avatarLoading.value = false;
}
}
</script>
<template>
<div class="flex justify-end space-x-4">
<button class="btn btn-secondary" @click="emit('cancel')">
{{ $t("general.cancel") }}
</button>
<button class="btn btn-primary" @click="save">
{{ $t("general.save") }}
</button>
</div>
<div v-if="error" class="flex items-center space-x-3 bg-red-200 px-6 py-3">
<it-icon-close class="h-8 w-8 text-red-800" />
<span>
{{
$t(
"a.Bitte überprüfe deine Eingaben. Es sind Fehler in deinem Formular aufgetreten."
)
}}
</span>
</div>
<div class="mb-4 bg-white p-3 md:p-6">
<h3 class="mb-8">{{ $t("a.Persönliche Informationen") }}</h3>
<section>
<label for="first-name" class="block pb-1.5 leading-6">
{{ $t("a.Vorname") }}
</label>
<input
id="first-name"
v-model="formData.first_name"
type="text"
name="first-name"
autocomplete="given-name"
disabled
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:max-w-sm sm:text-sm sm:leading-6"
/>
<label for="last-name" class="block pb-1.5 leading-6">
{{ $t("a.Name") }}
</label>
<input
id="last-name"
v-model="formData.last_name"
type="text"
name="last-name"
autocomplete="family-name"
disabled
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:max-w-sm sm:text-sm sm:leading-6"
/>
<label for="email" class="block pb-1.5 leading-6">
{{ $t("a.E-Mail Adresse") }}
</label>
<input
id="email"
:value="formData.email"
type="email"
name="email"
autocomplete="email"
disabled
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:max-w-sm sm:text-sm sm:leading-6"
/>
<label class="block pb-1.5 leading-6">
{{ $t("a.Profilbild") }}
</label>
<div class="flex items-center space-x-4">
<AvatarImage
:image-size="64"
:loading="avatarLoading"
:image-url="user.avatar_url"
/>
<div class="btn-secondary relative inline-flex cursor-pointer items-center">
<input
id="upload"
type="file"
class="absolute bottom-0 left-0 right-0 top-0 opacity-0"
accept="image/*"
:disabled="avatarLoading"
@change="avatarUpload"
/>
{{ $t("a.Bild hochladen") }}
<it-icon-upload class="it-icon ml-2 h-6 w-6" />
</div>
</div>
</section>
<section class="mt-8 border-t pt-8">
<h4 class="mb-4 text-lg font-bold">
{{ $t("a.Privatadresse") }}
</h4>
<div class="flex flex-col justify-start md:flex-row md:space-x-4">
<div class="w-full md:max-w-sm">
<label for="street-address" class="block pb-1.5 leading-6">
{{ $t("a.Strasse") }}
</label>
<input
id="street-address"
v-model="formData.street"
type="text"
name="street-address"
autocomplete="street-address"
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:text-sm sm:leading-6"
/>
</div>
<div class="w-full md:max-w-[160px]">
<label for="street-number" class="block pb-1.5 leading-6">
{{ $t("a.Hausnummmer") }}
</label>
<input
id="street-number"
v-model="formData.street_number"
name="street-number"
type="text"
autocomplete="street-number"
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div class="flex flex-col justify-start md:flex-row md:space-x-4">
<div class="w-full md:max-w-[160px]">
<label for="postal-code" class="block pb-1.5 leading-6">
{{ $t("a.PLZ") }}
</label>
<input
id="postal-code"
v-model="formData.postal_code"
name="postal-code"
type="text"
autocomplete="postal-code"
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:text-sm sm:leading-6"
/>
</div>
<div class="w-full md:max-w-sm">
<label for="city" class="block pb-1.5 leading-6">
{{ $t("a.Ort") }}
</label>
<input
id="city"
v-model="formData.city"
type="text"
name="city"
autocomplete="address-level2"
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:text-sm sm:leading-6"
/>
</div>
</div>
<label for="country" class="block pb-1.5 leading-6">
{{ $t("a.Land") }}
</label>
<select
id="country"
v-model="formData.country_id"
name="country"
autocomplete="country-name"
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:max-w-sm sm:text-sm sm:leading-6"
>
<option v-for="country in countries" :key="country.id" :value="country.id">
{{ country.name }}
</option>
</select>
</section>
</div>
<div class="mb-4 bg-white p-3 md:p-6">
<h3 class="mb-8">{{ $t("a.Geschäftsdaten") }}</h3>
<section>
<label for="organisation" class="block pb-1.5 leading-6">
{{ $t("a.Unternehmen") }}
</label>
<select
id="organisation"
v-model="formData.organisation"
required
name="organisation"
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:max-w-sm sm:text-sm sm:leading-6"
>
<option
v-for="organisation in organisations"
:key="organisation.id"
:value="organisation.id"
>
{{ organisation.name }}
</option>
</select>
</section>
<section class="mt-8 border-t pt-8">
<h4 class="mb-4 text-lg font-bold">
{{ $t("a.Firmenanschrift") }}
</h4>
<div class="flex flex-col justify-start md:flex-row md:space-x-4">
<div class="w-full md:max-w-sm">
<label for="org-street-address" class="block pb-1.5 leading-6">
{{ $t("a.Strasse") }}
</label>
<input
id="org-street-address"
v-model="formData.organisation_street"
type="text"
name="org-street-address"
autocomplete="street-address"
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:text-sm sm:leading-6"
/>
</div>
<div class="w-full md:max-w-[160px]">
<label for="org-street-number" class="block pb-1.5 leading-6">
{{ $t("a.Hausnummmer") }}
</label>
<input
id="org-street-number"
v-model="formData.organisation_street_number"
name="org-street-number"
type="text"
autocomplete="street-number"
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div class="flex flex-col justify-start md:flex-row md:space-x-4">
<div class="w-full md:max-w-[160px]">
<label for="org-postal-code" class="block pb-1.5 leading-6">
{{ $t("a.PLZ") }}
</label>
<input
id="org-postal-code"
v-model="formData.organisation_postal_code"
name="org-postal-code"
type="text"
autocomplete="postal-code"
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:text-sm sm:leading-6"
/>
</div>
<div class="w-full md:max-w-sm">
<label for="org-city" class="block pb-1.5 leading-6">
{{ $t("a.Ort") }}
</label>
<input
id="org-city"
v-model="formData.organisation_city"
type="text"
name="org-city"
autocomplete="address-level2"
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:text-sm sm:leading-6"
/>
</div>
</div>
<label for="org-country" class="block pb-1.5 leading-6">
{{ $t("a.Land") }}
</label>
<select
id="org-country"
v-model="formData.organisation_country_id"
required
name="org-country"
autocomplete="country-name"
class="disabled:bg-gray-50 mb-4 block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 disabled:cursor-not-allowed disabled:text-gray-500 disabled:ring-gray-200 sm:max-w-sm sm:text-sm sm:leading-6"
>
<option v-for="country in countries" :key="country.id" :value="country.id">
{{ country.name }}
</option>
</select>
</section>
</div>
<div class="mb-4 bg-white p-3 md:p-6">
<h3 class="mb-8">{{ $t("a.Rechnungsadresse") }}</h3>
<fieldset class="mt-4">
<legend class="sr-only">Notification method</legend>
<div class="space-y-4">
<div class="flex items-center">
<input
id="invoice-address-private"
v-model="formData.invoice_address"
type="radio"
value="prv"
class="h-4 w-4 border-gray-300 text-blue-600 focus:ring-blue-600"
/>
<label
for="invoice-address-private"
class="ml-3 block text-sm font-medium leading-6 text-gray-900"
>
{{ $t("a.Gleich wie die Privatadresse") }}
</label>
</div>
<div class="flex items-center">
<input
id="invoice-address-organisation"
v-model="formData.invoice_address"
type="radio"
value="org"
class="h-4 w-4 border-gray-300 text-blue-600 focus:ring-blue-600"
/>
<label
for="invoice-address-organisation"
class="ml-3 block text-sm font-medium leading-6 text-gray-900"
>
{{ $t("a.Gleich wie die Firmenanschrift") }}
</label>
</div>
</div>
</fieldset>
</div>
<div class="flex justify-end space-x-4">
<button class="btn btn-secondary" @click="emit('cancel')">
{{ $t("general.cancel") }}
</button>
<button class="btn btn-primary" @click="save">
{{ $t("general.save") }}
</button>
</div>
</template>