Add more editable profile fields
This commit is contained in:
parent
47896444a6
commit
d56c346512
|
|
@ -3,6 +3,8 @@ import { useEntities } from "@/services/entities";
|
||||||
import AvatarImage from "@/components/ui/AvatarImage.vue";
|
import AvatarImage from "@/components/ui/AvatarImage.vue";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { type User, useUserStore } from "@/stores/user";
|
import { type User, useUserStore } from "@/stores/user";
|
||||||
|
import ItDatePicker from "@/components/ui/ItDatePicker.vue";
|
||||||
|
import { normalizeSwissPhoneNumber } from "@/utils/phone";
|
||||||
|
|
||||||
const emit = defineEmits(["cancel", "save"]);
|
const emit = defineEmits(["cancel", "save"]);
|
||||||
|
|
||||||
|
|
@ -26,6 +28,7 @@ const formData = ref({
|
||||||
birth_date: user.birth_date,
|
birth_date: user.birth_date,
|
||||||
|
|
||||||
organisation: user.organisation,
|
organisation: user.organisation,
|
||||||
|
organisation_detail_name: user.organisation_detail_name,
|
||||||
organisation_street: user.organisation_street,
|
organisation_street: user.organisation_street,
|
||||||
organisation_street_number: user.organisation_street_number,
|
organisation_street_number: user.organisation_street_number,
|
||||||
organisation_postal_code: user.organisation_postal_code,
|
organisation_postal_code: user.organisation_postal_code,
|
||||||
|
|
@ -35,7 +38,8 @@ const formData = ref({
|
||||||
});
|
});
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
const { country_code, organisation_country_code, ...profileData } = formData.value;
|
const { country_code, organisation_country_code, phone_number, ...profileData } =
|
||||||
|
formData.value;
|
||||||
const typedProfileData: Partial<User> = { ...profileData };
|
const typedProfileData: Partial<User> = { ...profileData };
|
||||||
|
|
||||||
typedProfileData.country = countries.value.find(
|
typedProfileData.country = countries.value.find(
|
||||||
|
|
@ -45,6 +49,10 @@ async function save() {
|
||||||
(c) => c.country_code === organisation_country_code
|
(c) => c.country_code === organisation_country_code
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (phone_number) {
|
||||||
|
typedProfileData.phone_number = normalizeSwissPhoneNumber(phone_number);
|
||||||
|
}
|
||||||
|
|
||||||
await user.updateUserProfile(typedProfileData);
|
await user.updateUserProfile(typedProfileData);
|
||||||
emit("save");
|
emit("save");
|
||||||
}
|
}
|
||||||
|
|
@ -130,6 +138,28 @@ async function avatarUpload(e: Event) {
|
||||||
disabled
|
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"
|
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="phone" class="block pb-1.5 leading-6">
|
||||||
|
{{ $t("a.Telefonnummer") }}
|
||||||
|
</label>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
id="phone"
|
||||||
|
v-model="formData.phone_number"
|
||||||
|
type="text"
|
||||||
|
name="phone"
|
||||||
|
autocomplete="phone-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:max-w-sm sm:text-sm sm:leading-6"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="birth-date" class="block pb-1.5 leading-6">
|
||||||
|
{{ $t("a.Geburtsdatum") }}
|
||||||
|
</label>
|
||||||
|
<div class="mb-4 block w-full py-1.5 sm:max-w-sm sm:text-sm sm:leading-6">
|
||||||
|
<ItDatePicker v-model="formData.birth_date"></ItDatePicker>
|
||||||
|
</div>
|
||||||
|
|
||||||
<label class="block pb-1.5 leading-6">
|
<label class="block pb-1.5 leading-6">
|
||||||
{{ $t("a.Profilbild") }}
|
{{ $t("a.Profilbild") }}
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -268,6 +298,22 @@ async function avatarUpload(e: Event) {
|
||||||
{{ $t("a.Firmenanschrift") }}
|
{{ $t("a.Firmenanschrift") }}
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
|
<div class="flex flex-col justify-start md:flex-row md:space-x-4">
|
||||||
|
<div class="w-full md:max-w-lg">
|
||||||
|
<label for="org-street-address" class="block pb-1.5 leading-6">
|
||||||
|
{{ $t("a.Name") }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
id="org-detail-name"
|
||||||
|
v-model="formData.organisation_detail_name"
|
||||||
|
type="text"
|
||||||
|
name="org-detail-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:text-sm sm:leading-6"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col justify-start md:flex-row md:space-x-4">
|
<div class="flex flex-col justify-start md:flex-row md:space-x-4">
|
||||||
<div class="w-full md:max-w-sm">
|
<div class="w-full md:max-w-sm">
|
||||||
<label for="org-street-address" class="block pb-1.5 leading-6">
|
<label for="org-street-address" class="block pb-1.5 leading-6">
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import { useUserStore } from "@/stores/user";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import { useEntities } from "@/services/entities";
|
import { useEntities } from "@/services/entities";
|
||||||
import { useTranslation } from "i18next-vue";
|
import { useTranslation } from "i18next-vue";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import { displaySwissPhoneNumber } from "@/utils/phone";
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
|
@ -10,21 +12,20 @@ const user = useUserStore();
|
||||||
const { organisations } = useEntities();
|
const { organisations } = useEntities();
|
||||||
|
|
||||||
const privateAddress = computed(() => {
|
const privateAddress = computed(() => {
|
||||||
let addressText = `${user.street} ${user.street_number}`.trim();
|
const textParts = [];
|
||||||
if (user.postal_code || user.city) {
|
|
||||||
if (addressText.length) {
|
if (user.street || user.street_number) {
|
||||||
addressText += ", ";
|
textParts.push(`${user.street} ${user.street_number}`.trim());
|
||||||
}
|
|
||||||
addressText += `${user.postal_code} ${user.city}`;
|
|
||||||
}
|
|
||||||
if (user.country) {
|
|
||||||
if (addressText.length) {
|
|
||||||
addressText += ", ";
|
|
||||||
}
|
|
||||||
addressText += user.country.name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return addressText.trim();
|
if (user.postal_code || user.city) {
|
||||||
|
textParts.push(`${user.postal_code} ${user.city}`);
|
||||||
|
}
|
||||||
|
if (textParts.length && user.country) {
|
||||||
|
textParts.push(user.country.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return textParts;
|
||||||
});
|
});
|
||||||
|
|
||||||
const organisationName = computed(() => {
|
const organisationName = computed(() => {
|
||||||
|
|
@ -36,22 +37,25 @@ const organisationName = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const orgAddress = computed(() => {
|
const orgAddress = computed(() => {
|
||||||
let addressText =
|
const textParts = [];
|
||||||
`${user.organisation_street} ${user.organisation_street_number}`.trim();
|
|
||||||
if (user.organisation_postal_code || user.organisation_city) {
|
if (user.organisation_detail_name) {
|
||||||
if (addressText.length) {
|
textParts.push(user.organisation_detail_name);
|
||||||
addressText += ", ";
|
|
||||||
}
|
|
||||||
addressText += `${user.organisation_postal_code} ${user.organisation_city}`;
|
|
||||||
}
|
|
||||||
if (user.organisation_country) {
|
|
||||||
if (addressText.length) {
|
|
||||||
addressText += ", ";
|
|
||||||
}
|
|
||||||
addressText += user.organisation_country.name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return addressText.trim();
|
if (user.organisation_street || user.organisation_street_number) {
|
||||||
|
textParts.push(
|
||||||
|
`${user.organisation_street} ${user.organisation_street_number}`.trim()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (user.organisation_postal_code || user.organisation_city) {
|
||||||
|
textParts.push(`${user.organisation_postal_code} ${user.organisation_city}`);
|
||||||
|
}
|
||||||
|
if (textParts.length && user.organisation_country) {
|
||||||
|
textParts.push(user.organisation_country.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return textParts;
|
||||||
});
|
});
|
||||||
|
|
||||||
const invoiceAddress = computed(() => {
|
const invoiceAddress = computed(() => {
|
||||||
|
|
@ -74,13 +78,34 @@ const invoiceAddress = computed(() => {
|
||||||
{{ $t("a.E-Mail Adresse") }}
|
{{ $t("a.E-Mail Adresse") }}
|
||||||
</label>
|
</label>
|
||||||
<div class="mb-3 sm:col-span-2 sm:mb-0">{{ user.email }}</div>
|
<div class="mb-3 sm:col-span-2 sm:mb-0">{{ user.email }}</div>
|
||||||
|
<label class="block font-semibold leading-6">
|
||||||
|
{{ $t("a.Telefonnummer") }}
|
||||||
|
</label>
|
||||||
|
<div class="mb-3 sm:col-span-2 sm:mb-0">
|
||||||
|
<span v-if="user.phone_number">
|
||||||
|
{{ displaySwissPhoneNumber(user.phone_number) }}
|
||||||
|
</span>
|
||||||
|
<span v-else class="text-gray-800">{{ $t("a.Keine Angabe") }}</span>
|
||||||
|
</div>
|
||||||
|
<label class="block font-semibold leading-6">
|
||||||
|
{{ $t("a.Geburtsdatum") }}
|
||||||
|
</label>
|
||||||
|
<div class="mb-3 sm:col-span-2 sm:mb-0">
|
||||||
|
<span v-if="user.birth_date">
|
||||||
|
{{ dayjs(user.birth_date).format("DD.MM.YYYY") }}
|
||||||
|
</span>
|
||||||
|
<span v-else class="text-gray-800">{{ $t("a.Keine Angabe") }}</span>
|
||||||
|
</div>
|
||||||
<label class="block font-semibold leading-6">
|
<label class="block font-semibold leading-6">
|
||||||
{{ $t("a.Privatadresse") }}
|
{{ $t("a.Privatadresse") }}
|
||||||
</label>
|
</label>
|
||||||
<div class="mb-3 sm:col-span-2 sm:mb-0">
|
<div class="mb-3 sm:col-span-2 sm:mb-0">
|
||||||
<template v-if="privateAddress">
|
<div v-if="privateAddress.length">
|
||||||
{{ privateAddress }}
|
<span v-for="(line, index) in privateAddress" :key="index">
|
||||||
</template>
|
{{ line }}
|
||||||
|
<br />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<span v-else class="text-gray-800">{{ $t("a.Keine Angabe") }}</span>
|
<span v-else class="text-gray-800">{{ $t("a.Keine Angabe") }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -94,9 +119,13 @@ const invoiceAddress = computed(() => {
|
||||||
{{ $t("a.Firmenanschrift") }}
|
{{ $t("a.Firmenanschrift") }}
|
||||||
</label>
|
</label>
|
||||||
<div class="sm:col-span-2">
|
<div class="sm:col-span-2">
|
||||||
<template v-if="orgAddress">
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
{{ orgAddress }}
|
<div v-if="orgAddress">
|
||||||
</template>
|
<span v-for="(line, index) in orgAddress" :key="index">
|
||||||
|
{{ line }}
|
||||||
|
<br />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<span v-else class="text-gray-800">{{ $t("a.Keine Angabe") }}</span>
|
<span v-else class="text-gray-800">{{ $t("a.Keine Angabe") }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import VueDatePicker from "@vuepic/vue-datepicker";
|
import VueDatePicker from "@vuepic/vue-datepicker";
|
||||||
|
import "@vuepic/vue-datepicker/dist/main.css";
|
||||||
import { defineProps, withDefaults, defineModel } from "vue";
|
import { defineProps, withDefaults, defineModel } from "vue";
|
||||||
|
|
||||||
const model = defineModel<string>();
|
const model = defineModel<string>();
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ import VerticalBarChart from "@/components/ui/VerticalBarChart.vue";
|
||||||
import LearningPathCircle from "@/pages/learningPath/learningPathPage/LearningPathCircle.vue";
|
import LearningPathCircle from "@/pages/learningPath/learningPathPage/LearningPathCircle.vue";
|
||||||
import logger from "loglevel";
|
import logger from "loglevel";
|
||||||
import { reactive, ref } from "vue";
|
import { reactive, ref } from "vue";
|
||||||
|
import VueDatePicker from "@vuepic/vue-datepicker";
|
||||||
|
import "@vuepic/vue-datepicker/dist/main.css";
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
checkboxValue: true,
|
checkboxValue: true,
|
||||||
|
|
@ -34,6 +36,8 @@ const state = reactive({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const birtDate = ref("1982-06-15");
|
||||||
|
|
||||||
const dropdownData = [
|
const dropdownData = [
|
||||||
{
|
{
|
||||||
title: "Option 1",
|
title: "Option 1",
|
||||||
|
|
@ -411,6 +415,11 @@ function log(data: any) {
|
||||||
></ItDropdownSelect>
|
></ItDropdownSelect>
|
||||||
{{ state.dropdownSelected }}
|
{{ state.dropdownSelected }}
|
||||||
|
|
||||||
|
<h2 class="mb-8 mt-8">Date Picker</h2>
|
||||||
|
<div class="mt-2">
|
||||||
|
<VueDatePicker v-model="birthDate"></VueDatePicker>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2 class="mb-8 mt-8">Checkbox</h2>
|
<h2 class="mb-8 mt-8">Checkbox</h2>
|
||||||
|
|
||||||
<ItCheckbox
|
<ItCheckbox
|
||||||
|
|
|
||||||
|
|
@ -114,8 +114,9 @@ class User(AbstractUser):
|
||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# fields gathered from cembra pay form
|
|
||||||
birth_date = models.DateField(null=True, blank=True)
|
birth_date = models.DateField(null=True, blank=True)
|
||||||
|
|
||||||
|
# phone number should be stored in the format +41792018586 (not validated)
|
||||||
phone_number = models.CharField(max_length=255, blank=True, default="")
|
phone_number = models.CharField(max_length=255, blank=True, default="")
|
||||||
|
|
||||||
# is only set by abacus invoice export code
|
# is only set by abacus invoice export code
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue