mirror of
https://github.com/Novaloop-AG/healthchat-web.git
synced 2026-11-05 22:25:36 +00:00
feat: improve profile view with additional fields and validation
This commit is contained in:
@@ -32,6 +32,37 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Business contact field specific layouts */
|
||||||
|
.mx_ExtendedProfileSettings_address_row {
|
||||||
|
.mx_ExtendedProfileSettings_field_business_street {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_ExtendedProfileSettings_field_business_street_nr {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_ExtendedProfileSettings_postal_row {
|
||||||
|
.mx_ExtendedProfileSettings_field_business_plz {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_ExtendedProfileSettings_field_business_city {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_ExtendedProfileSettings_contact_row {
|
||||||
|
.mx_ExtendedProfileSettings_field_business_email {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_ExtendedProfileSettings_field_business_tel {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.mx_ExtendedProfileSettings_buttons {
|
.mx_ExtendedProfileSettings_buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import { SdkContextClass } from "../../../contexts/SDKContext";
|
|||||||
import { Container } from "../right_panel/UserInfo";
|
import { Container } from "../right_panel/UserInfo";
|
||||||
import InlineSpinner from "../elements/InlineSpinner";
|
import InlineSpinner from "../elements/InlineSpinner";
|
||||||
import {
|
import {
|
||||||
EXT_PROFILE_KEY_ADDRESS,
|
|
||||||
EXT_PROFILE_KEY_FURTHER_INFO,
|
EXT_PROFILE_KEY_FURTHER_INFO,
|
||||||
EXT_PROFILE_KEY_SPECIALIZATION,
|
EXT_PROFILE_KEY_SPECIALIZATION,
|
||||||
EXT_PROFILE_KEY_TITLE,
|
EXT_PROFILE_KEY_TITLE,
|
||||||
@@ -61,13 +60,11 @@ const ExtendedProfileView: React.FC<ExtendedProfileViewProps> = ({ userId }) =>
|
|||||||
const [
|
const [
|
||||||
titleValue,
|
titleValue,
|
||||||
specializationValue,
|
specializationValue,
|
||||||
addressValue,
|
|
||||||
websiteValue,
|
websiteValue,
|
||||||
furtherInfoValue,
|
furtherInfoValue,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_TITLE),
|
userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_TITLE),
|
||||||
userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_SPECIALIZATION),
|
userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_SPECIALIZATION),
|
||||||
userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_ADDRESS),
|
|
||||||
userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_WEBSITE),
|
userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_WEBSITE),
|
||||||
userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_FURTHER_INFO),
|
userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_FURTHER_INFO),
|
||||||
]);
|
]);
|
||||||
@@ -75,7 +72,6 @@ const ExtendedProfileView: React.FC<ExtendedProfileViewProps> = ({ userId }) =>
|
|||||||
const data = {
|
const data = {
|
||||||
title: titleValue as string | null,
|
title: titleValue as string | null,
|
||||||
specialization: specializationValue as string | null,
|
specialization: specializationValue as string | null,
|
||||||
address: addressValue as string | null,
|
|
||||||
website: websiteValue as string | null,
|
website: websiteValue as string | null,
|
||||||
furtherInfo: furtherInfoValue as string | null,
|
furtherInfo: furtherInfoValue as string | null,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,13 @@ import { _t } from "../../../languageHandler";
|
|||||||
import {
|
import {
|
||||||
EXT_PROFILE_KEY_TITLE,
|
EXT_PROFILE_KEY_TITLE,
|
||||||
EXT_PROFILE_KEY_SPECIALIZATION,
|
EXT_PROFILE_KEY_SPECIALIZATION,
|
||||||
EXT_PROFILE_KEY_ADDRESS,
|
EXT_PROFILE_KEY_PRACTICE_NAME,
|
||||||
|
EXT_PROFILE_KEY_BUSINESS_STREET,
|
||||||
|
EXT_PROFILE_KEY_BUSINESS_STREET_NR,
|
||||||
|
EXT_PROFILE_KEY_BUSINESS_CITY,
|
||||||
|
EXT_PROFILE_KEY_BUSINESS_PLZ,
|
||||||
|
EXT_PROFILE_KEY_BUSINESS_EMAIL,
|
||||||
|
EXT_PROFILE_KEY_BUSINESS_TEL,
|
||||||
EXT_PROFILE_KEY_WEBSITE,
|
EXT_PROFILE_KEY_WEBSITE,
|
||||||
EXT_PROFILE_KEY_FURTHER_INFO,
|
EXT_PROFILE_KEY_FURTHER_INFO,
|
||||||
} from "../settings/ExtendedProfileSettings";
|
} from "../settings/ExtendedProfileSettings";
|
||||||
@@ -41,7 +47,13 @@ const UserExtendedProfileInfo: React.FC<UserExtendedProfileInfoProps> = ({ userI
|
|||||||
|
|
||||||
const [title, setTitle] = useState<string>("");
|
const [title, setTitle] = useState<string>("");
|
||||||
const [specialization, setSpecialization] = useState<string>("");
|
const [specialization, setSpecialization] = useState<string>("");
|
||||||
const [address, setAddress] = useState<string>("");
|
const [practiceName, setPracticeName] = useState<string>("");
|
||||||
|
const [businessStreet, setBusinessStreet] = useState<string>("");
|
||||||
|
const [businessStreetNr, setBusinessStreetNr] = useState<string>("");
|
||||||
|
const [businessCity, setBusinessCity] = useState<string>("");
|
||||||
|
const [businessPlz, setBusinessPlz] = useState<string>("");
|
||||||
|
const [businessEmail, setBusinessEmail] = useState<string>("");
|
||||||
|
const [businessTel, setBusinessTel] = useState<string>("");
|
||||||
const [website, setWebsite] = useState<string>("");
|
const [website, setWebsite] = useState<string>("");
|
||||||
const [furtherInfo, setFurtherInfo] = useState<string>("");
|
const [furtherInfo, setFurtherInfo] = useState<string>("");
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
@@ -55,13 +67,25 @@ const UserExtendedProfileInfo: React.FC<UserExtendedProfileInfoProps> = ({ userI
|
|||||||
|
|
||||||
const titleValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_TITLE);
|
const titleValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_TITLE);
|
||||||
const specializationValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_SPECIALIZATION);
|
const specializationValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_SPECIALIZATION);
|
||||||
const addressValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_ADDRESS);
|
const practiceNameValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_PRACTICE_NAME);
|
||||||
|
const businessStreetValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_BUSINESS_STREET);
|
||||||
|
const businessStreetNrValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_BUSINESS_STREET_NR);
|
||||||
|
const businessCityValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_BUSINESS_CITY);
|
||||||
|
const businessPlzValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_BUSINESS_PLZ);
|
||||||
|
const businessEmailValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_BUSINESS_EMAIL);
|
||||||
|
const businessTelValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_BUSINESS_TEL);
|
||||||
const websiteValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_WEBSITE);
|
const websiteValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_WEBSITE);
|
||||||
const furtherInfoValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_FURTHER_INFO);
|
const furtherInfoValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_FURTHER_INFO);
|
||||||
|
|
||||||
setTitle(titleValue as string || "");
|
setTitle(titleValue as string || "");
|
||||||
setSpecialization(specializationValue as string || "");
|
setSpecialization(specializationValue as string || "");
|
||||||
setAddress(addressValue as string || "");
|
setPracticeName(practiceNameValue as string || "");
|
||||||
|
setBusinessStreet(businessStreetValue as string || "");
|
||||||
|
setBusinessStreetNr(businessStreetNrValue as string || "");
|
||||||
|
setBusinessCity(businessCityValue as string || "");
|
||||||
|
setBusinessPlz(businessPlzValue as string || "");
|
||||||
|
setBusinessEmail(businessEmailValue as string || "");
|
||||||
|
setBusinessTel(businessTelValue as string || "");
|
||||||
setWebsite(websiteValue as string || "");
|
setWebsite(websiteValue as string || "");
|
||||||
setFurtherInfo(furtherInfoValue as string || "");
|
setFurtherInfo(furtherInfoValue as string || "");
|
||||||
} catch {
|
} catch {
|
||||||
@@ -83,15 +107,12 @@ const UserExtendedProfileInfo: React.FC<UserExtendedProfileInfoProps> = ({ userI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't render anything if there's no data
|
// Don't render anything if there's no data
|
||||||
if (!title && !specialization && !address && !website && !furtherInfo) {
|
if (!title && !specialization && !practiceName && !businessStreet && !businessStreetNr && !businessCity && !businessPlz && !businessEmail && !businessTel && !website && !furtherInfo) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_UserInfo_container mx_UserInfo_profileInfo">
|
<div className="mx_UserInfo_container mx_UserInfo_profileInfo">
|
||||||
{/* <div className="mx_UserInfo_container_header">
|
|
||||||
<Text weight="semibold">{_t("user_info|extended_profile|header")}</Text>
|
|
||||||
</div> */}
|
|
||||||
{title && (
|
{title && (
|
||||||
<div className="mx_UserInfo_profileField">
|
<div className="mx_UserInfo_profileField">
|
||||||
<div className="mx_UserInfo_fieldLabel">
|
<div className="mx_UserInfo_fieldLabel">
|
||||||
@@ -116,7 +137,19 @@ const UserExtendedProfileInfo: React.FC<UserExtendedProfileInfoProps> = ({ userI
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{address && (
|
{practiceName && (
|
||||||
|
<div className="mx_UserInfo_profileField">
|
||||||
|
<div className="mx_UserInfo_fieldLabel">
|
||||||
|
<Text size="sm" weight="semibold">
|
||||||
|
{_t("user_info|extended_profile|practice_name")}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<div className="mx_UserInfo_fieldValue">
|
||||||
|
<Text size="sm">{practiceName}</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{businessStreet && businessCity && (
|
||||||
<div className="mx_UserInfo_profileField">
|
<div className="mx_UserInfo_profileField">
|
||||||
<div className="mx_UserInfo_fieldLabel">
|
<div className="mx_UserInfo_fieldLabel">
|
||||||
<Text size="sm" weight="semibold">
|
<Text size="sm" weight="semibold">
|
||||||
@@ -124,7 +157,39 @@ const UserExtendedProfileInfo: React.FC<UserExtendedProfileInfoProps> = ({ userI
|
|||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_UserInfo_fieldValue">
|
<div className="mx_UserInfo_fieldValue">
|
||||||
<Text size="sm">{renderMultilineText(address)}</Text>
|
<Text size="sm">
|
||||||
|
{[businessStreet, businessStreetNr].filter(Boolean).join(" ")}
|
||||||
|
{(businessStreet || businessStreetNr) && (businessPlz || businessCity) && ", "}
|
||||||
|
{[businessPlz, businessCity].filter(Boolean).join(" ")}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{businessEmail && (
|
||||||
|
<div className="mx_UserInfo_profileField">
|
||||||
|
<div className="mx_UserInfo_fieldLabel">
|
||||||
|
<Text size="sm" weight="semibold">
|
||||||
|
{_t("user_info|extended_profile|business_email")}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<div className="mx_UserInfo_fieldValue">
|
||||||
|
<Text size="sm">
|
||||||
|
<a href={`mailto:${businessEmail}`}>{businessEmail}</a>
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{businessTel && (
|
||||||
|
<div className="mx_UserInfo_profileField">
|
||||||
|
<div className="mx_UserInfo_fieldLabel">
|
||||||
|
<Text size="sm" weight="semibold">
|
||||||
|
{_t("user_info|extended_profile|business_tel")}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<div className="mx_UserInfo_fieldValue">
|
||||||
|
<Text size="sm">
|
||||||
|
<a href={`tel:${businessTel}`}>{businessTel}</a>
|
||||||
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
|
|
||||||
import React, { type ChangeEvent, useCallback, useEffect, useState } from "react";
|
import React, { type ChangeEvent, useCallback, useEffect, useState } from "react";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { Alert, ErrorMessage } from "@vector-im/compound-web";
|
import { Alert } from "@vector-im/compound-web";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
@@ -28,9 +28,15 @@ const SpinnerToast: React.FC<{ children?: React.ReactNode }> = ({ children }) =>
|
|||||||
// Extended profile property keys
|
// Extended profile property keys
|
||||||
export const EXT_PROFILE_KEY_TITLE = "io.element.profile.title";
|
export const EXT_PROFILE_KEY_TITLE = "io.element.profile.title";
|
||||||
export const EXT_PROFILE_KEY_SPECIALIZATION = "io.element.profile.specialization";
|
export const EXT_PROFILE_KEY_SPECIALIZATION = "io.element.profile.specialization";
|
||||||
export const EXT_PROFILE_KEY_ADDRESS = "io.element.profile.address";
|
|
||||||
export const EXT_PROFILE_KEY_WEBSITE = "io.element.profile.website";
|
export const EXT_PROFILE_KEY_WEBSITE = "io.element.profile.website";
|
||||||
export const EXT_PROFILE_KEY_FURTHER_INFO = "io.element.profile.further_info";
|
export const EXT_PROFILE_KEY_FURTHER_INFO = "io.element.profile.further_info";
|
||||||
|
export const EXT_PROFILE_KEY_PRACTICE_NAME = "io.element.profile.practice_name";
|
||||||
|
export const EXT_PROFILE_KEY_BUSINESS_STREET = "io.element.profile.business_street";
|
||||||
|
export const EXT_PROFILE_KEY_BUSINESS_STREET_NR = "io.element.profile.business_street_nr";
|
||||||
|
export const EXT_PROFILE_KEY_BUSINESS_CITY = "io.element.profile.business_city";
|
||||||
|
export const EXT_PROFILE_KEY_BUSINESS_PLZ = "io.element.profile.business_plz";
|
||||||
|
export const EXT_PROFILE_KEY_BUSINESS_EMAIL = "io.element.profile.business_email";
|
||||||
|
export const EXT_PROFILE_KEY_BUSINESS_TEL = "io.element.profile.business_tel";
|
||||||
|
|
||||||
// Unstable feature key for extended profiles
|
// Unstable feature key for extended profiles
|
||||||
export const UNSTABLE_MSC4133_EXTENDED_PROFILES = "org.matrix.msc4133.extended_profiles";
|
export const UNSTABLE_MSC4133_EXTENDED_PROFILES = "org.matrix.msc4133.extended_profiles";
|
||||||
@@ -41,21 +47,41 @@ interface ExtendedProfileSettingsProps {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Component for managing extended profile fields for medical professionals.
|
* Component for managing extended profile fields for medical professionals.
|
||||||
* Allows editing title, specialization, address, website, and further information.
|
* Allows editing title, specialization, website, and further information.
|
||||||
*/
|
*/
|
||||||
const ExtendedProfileSettings: React.FC<ExtendedProfileSettingsProps> = ({ className }) => {
|
const ExtendedProfileSettings: React.FC<ExtendedProfileSettingsProps> = ({ className }) => {
|
||||||
const [title, setTitle] = useState<string>("");
|
const [title, setTitle] = useState<string>("");
|
||||||
const [specialization, setSpecialization] = useState<string>("");
|
const [specialization, setSpecialization] = useState<string>("");
|
||||||
const [address, setAddress] = useState<string>("");
|
|
||||||
const [website, setWebsite] = useState<string>("");
|
const [website, setWebsite] = useState<string>("");
|
||||||
const [furtherInfo, setFurtherInfo] = useState<string>("");
|
const [furtherInfo, setFurtherInfo] = useState<string>("");
|
||||||
|
const [practiceName, setPracticeName] = useState<string>("");
|
||||||
|
|
||||||
|
// Business contact field states
|
||||||
|
const [businessStreet, setBusinessStreet] = useState<string>("");
|
||||||
|
const [businessStreetNr, setBusinessStreetNr] = useState<string>("");
|
||||||
|
const [businessCity, setBusinessCity] = useState<string>("");
|
||||||
|
const [businessPlz, setBusinessPlz] = useState<string>("");
|
||||||
|
const [businessEmail, setBusinessEmail] = useState<string>("");
|
||||||
|
const [businessTel, setBusinessTel] = useState<string>("");
|
||||||
|
|
||||||
|
// Validation states for email and phone
|
||||||
|
const [businessEmailValid, setBusinessEmailValid] = useState<boolean>(true);
|
||||||
|
const [businessTelValid, setBusinessTelValid] = useState<boolean>(true);
|
||||||
|
|
||||||
// Store original values for cancel functionality
|
// Store original values for cancel functionality
|
||||||
const [originalTitle, setOriginalTitle] = useState<string>("");
|
const [originalTitle, setOriginalTitle] = useState<string>("");
|
||||||
const [originalSpecialization, setOriginalSpecialization] = useState<string>("");
|
const [originalSpecialization, setOriginalSpecialization] = useState<string>("");
|
||||||
const [originalAddress, setOriginalAddress] = useState<string>("");
|
|
||||||
const [originalWebsite, setOriginalWebsite] = useState<string>("");
|
const [originalWebsite, setOriginalWebsite] = useState<string>("");
|
||||||
const [originalFurtherInfo, setOriginalFurtherInfo] = useState<string>("");
|
const [originalFurtherInfo, setOriginalFurtherInfo] = useState<string>("");
|
||||||
|
const [originalPracticeName, setOriginalPracticeName] = useState<string>("");
|
||||||
|
|
||||||
|
// Original business contact field values
|
||||||
|
const [originalBusinessStreet, setOriginalBusinessStreet] = useState<string>("");
|
||||||
|
const [originalBusinessStreetNr, setOriginalBusinessStreetNr] = useState<string>("");
|
||||||
|
const [originalBusinessCity, setOriginalBusinessCity] = useState<string>("");
|
||||||
|
const [originalBusinessPlz, setOriginalBusinessPlz] = useState<string>("");
|
||||||
|
const [originalBusinessEmail, setOriginalBusinessEmail] = useState<string>("");
|
||||||
|
const [originalBusinessTel, setOriginalBusinessTel] = useState<string>("");
|
||||||
|
|
||||||
const [isModified, setIsModified] = useState<boolean>(false);
|
const [isModified, setIsModified] = useState<boolean>(false);
|
||||||
const [isSaving, setIsSaving] = useState<boolean>(false);
|
const [isSaving, setIsSaving] = useState<boolean>(false);
|
||||||
@@ -76,28 +102,60 @@ const ExtendedProfileSettings: React.FC<ExtendedProfileSettingsProps> = ({ class
|
|||||||
try {
|
try {
|
||||||
const titleValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_TITLE);
|
const titleValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_TITLE);
|
||||||
const specializationValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_SPECIALIZATION);
|
const specializationValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_SPECIALIZATION);
|
||||||
const addressValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_ADDRESS);
|
|
||||||
const websiteValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_WEBSITE);
|
const websiteValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_WEBSITE);
|
||||||
const furtherInfoValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_FURTHER_INFO);
|
const furtherInfoValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_FURTHER_INFO);
|
||||||
|
const practiceNameValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_PRACTICE_NAME);
|
||||||
|
|
||||||
|
// Fetch business contact fields
|
||||||
|
const businessStreetValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_BUSINESS_STREET);
|
||||||
|
const businessStreetNrValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_BUSINESS_STREET_NR);
|
||||||
|
const businessCityValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_BUSINESS_CITY);
|
||||||
|
const businessPlzValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_BUSINESS_PLZ);
|
||||||
|
const businessEmailValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_BUSINESS_EMAIL);
|
||||||
|
const businessTelValue = await userProfilesStore.getOrFetchExtendedProfileProperty(userId, EXT_PROFILE_KEY_BUSINESS_TEL);
|
||||||
|
|
||||||
const titleStr = titleValue as string || "";
|
const titleStr = titleValue as string || "";
|
||||||
const specializationStr = specializationValue as string || "";
|
const specializationStr = specializationValue as string || "";
|
||||||
const addressStr = addressValue as string || "";
|
|
||||||
const websiteStr = websiteValue as string || "";
|
const websiteStr = websiteValue as string || "";
|
||||||
const furtherInfoStr = furtherInfoValue as string || "";
|
const furtherInfoStr = furtherInfoValue as string || "";
|
||||||
|
const practiceNameStr = practiceNameValue as string || "";
|
||||||
|
|
||||||
|
// Convert business contact field values to strings
|
||||||
|
const businessStreetStr = businessStreetValue as string || "";
|
||||||
|
const businessStreetNrStr = businessStreetNrValue as string || "";
|
||||||
|
const businessCityStr = businessCityValue as string || "";
|
||||||
|
const businessPlzStr = businessPlzValue as string || "";
|
||||||
|
const businessEmailStr = businessEmailValue as string || "";
|
||||||
|
const businessTelStr = businessTelValue as string || "";
|
||||||
|
|
||||||
setTitle(titleStr);
|
setTitle(titleStr);
|
||||||
setSpecialization(specializationStr);
|
setSpecialization(specializationStr);
|
||||||
setAddress(addressStr);
|
|
||||||
setWebsite(websiteStr);
|
setWebsite(websiteStr);
|
||||||
setFurtherInfo(furtherInfoStr);
|
setFurtherInfo(furtherInfoStr);
|
||||||
|
setPracticeName(practiceNameStr);
|
||||||
|
|
||||||
|
// Set business contact fields
|
||||||
|
setBusinessStreet(businessStreetStr);
|
||||||
|
setBusinessStreetNr(businessStreetNrStr);
|
||||||
|
setBusinessCity(businessCityStr);
|
||||||
|
setBusinessPlz(businessPlzStr);
|
||||||
|
setBusinessEmail(businessEmailStr);
|
||||||
|
setBusinessTel(businessTelStr);
|
||||||
|
|
||||||
// Store original values for cancel functionality
|
// Store original values for cancel functionality
|
||||||
setOriginalTitle(titleStr);
|
setOriginalTitle(titleStr);
|
||||||
setOriginalSpecialization(specializationStr);
|
setOriginalSpecialization(specializationStr);
|
||||||
setOriginalAddress(addressStr);
|
|
||||||
setOriginalWebsite(websiteStr);
|
setOriginalWebsite(websiteStr);
|
||||||
setOriginalFurtherInfo(furtherInfoStr);
|
setOriginalFurtherInfo(furtherInfoStr);
|
||||||
|
setOriginalPracticeName(practiceNameStr);
|
||||||
|
|
||||||
|
// Store original business contact field values
|
||||||
|
setOriginalBusinessStreet(businessStreetStr);
|
||||||
|
setOriginalBusinessStreetNr(businessStreetNrStr);
|
||||||
|
setOriginalBusinessCity(businessCityStr);
|
||||||
|
setOriginalBusinessPlz(businessPlzStr);
|
||||||
|
setOriginalBusinessEmail(businessEmailStr);
|
||||||
|
setOriginalBusinessTel(businessTelStr);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Just log the error but don't set loadError to true
|
// Just log the error but don't set loadError to true
|
||||||
// as we want the fields to show up even when empty
|
// as we want the fields to show up even when empty
|
||||||
@@ -117,13 +175,24 @@ const ExtendedProfileSettings: React.FC<ExtendedProfileSettingsProps> = ({ class
|
|||||||
const hasChanges =
|
const hasChanges =
|
||||||
title !== originalTitle ||
|
title !== originalTitle ||
|
||||||
specialization !== originalSpecialization ||
|
specialization !== originalSpecialization ||
|
||||||
address !== originalAddress ||
|
|
||||||
website !== originalWebsite ||
|
website !== originalWebsite ||
|
||||||
furtherInfo !== originalFurtherInfo;
|
furtherInfo !== originalFurtherInfo ||
|
||||||
|
practiceName !== originalPracticeName ||
|
||||||
|
businessStreet !== originalBusinessStreet ||
|
||||||
|
businessStreetNr !== originalBusinessStreetNr ||
|
||||||
|
businessCity !== originalBusinessCity ||
|
||||||
|
businessPlz !== originalBusinessPlz ||
|
||||||
|
businessEmail !== originalBusinessEmail ||
|
||||||
|
businessTel !== originalBusinessTel;
|
||||||
|
|
||||||
setIsModified(hasChanges);
|
setIsModified(hasChanges);
|
||||||
}, [title, specialization, address, website, furtherInfo,
|
}, [
|
||||||
originalTitle, originalSpecialization, originalAddress, originalWebsite, originalFurtherInfo]);
|
title, specialization, website, furtherInfo, practiceName,
|
||||||
|
originalTitle, originalSpecialization, originalWebsite, originalFurtherInfo, originalPracticeName,
|
||||||
|
businessStreet, businessStreetNr, businessCity, businessPlz, businessEmail, businessTel,
|
||||||
|
originalBusinessStreet, originalBusinessStreetNr, originalBusinessCity, originalBusinessPlz,
|
||||||
|
originalBusinessEmail, originalBusinessTel
|
||||||
|
]);
|
||||||
|
|
||||||
// Field change handlers
|
// Field change handlers
|
||||||
const onTitleChanged = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const onTitleChanged = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
@@ -134,10 +203,6 @@ const ExtendedProfileSettings: React.FC<ExtendedProfileSettingsProps> = ({ class
|
|||||||
setSpecialization(e.target.value);
|
setSpecialization(e.target.value);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onAddressChanged = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setAddress(e.target.value);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onWebsiteChanged = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const onWebsiteChanged = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
setWebsite(e.target.value);
|
setWebsite(e.target.value);
|
||||||
}, []);
|
}, []);
|
||||||
@@ -146,19 +211,80 @@ const ExtendedProfileSettings: React.FC<ExtendedProfileSettingsProps> = ({ class
|
|||||||
setFurtherInfo(e.target.value);
|
setFurtherInfo(e.target.value);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const onPracticeNameChanged = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setPracticeName(e.target.value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Business contact field change handlers
|
||||||
|
const onBusinessStreetChanged = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setBusinessStreet(e.target.value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onBusinessStreetNrChanged = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setBusinessStreetNr(e.target.value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onBusinessCityChanged = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setBusinessCity(e.target.value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onBusinessPlzChanged = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setBusinessPlz(e.target.value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Email validation with simple regex
|
||||||
|
const onBusinessEmailChanged = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
setBusinessEmail(value);
|
||||||
|
// Email format validation - basic check for something@something.something
|
||||||
|
const emailValid = value === "" || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
||||||
|
setBusinessEmailValid(emailValid);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Phone validation
|
||||||
|
const onBusinessTelChanged = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
setBusinessTel(value);
|
||||||
|
// Phone format validation - allow digits, spaces, plus, minus, parentheses
|
||||||
|
const phoneValid = value === "" || /^[0-9+\-() ]+$/.test(value);
|
||||||
|
setBusinessTelValid(phoneValid);
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Cancel handler - restore all original values
|
// Cancel handler - restore all original values
|
||||||
const onCancel = useCallback(() => {
|
const onCancel = useCallback(() => {
|
||||||
setTitle(originalTitle);
|
setTitle(originalTitle);
|
||||||
setSpecialization(originalSpecialization);
|
setSpecialization(originalSpecialization);
|
||||||
setAddress(originalAddress);
|
|
||||||
setWebsite(originalWebsite);
|
setWebsite(originalWebsite);
|
||||||
setFurtherInfo(originalFurtherInfo);
|
setFurtherInfo(originalFurtherInfo);
|
||||||
}, [originalTitle, originalSpecialization, originalAddress, originalWebsite, originalFurtherInfo]);
|
setPracticeName(originalPracticeName);
|
||||||
|
|
||||||
|
// Reset business contact fields to original values
|
||||||
|
setBusinessStreet(originalBusinessStreet);
|
||||||
|
setBusinessStreetNr(originalBusinessStreetNr);
|
||||||
|
setBusinessCity(originalBusinessCity);
|
||||||
|
setBusinessPlz(originalBusinessPlz);
|
||||||
|
setBusinessEmail(originalBusinessEmail);
|
||||||
|
setBusinessTel(originalBusinessTel);
|
||||||
|
|
||||||
|
// Reset validation states
|
||||||
|
setBusinessEmailValid(true);
|
||||||
|
setBusinessTelValid(true);
|
||||||
|
}, [
|
||||||
|
originalTitle, originalSpecialization, originalWebsite, originalFurtherInfo, originalPracticeName,
|
||||||
|
originalBusinessStreet, originalBusinessStreetNr, originalBusinessCity, originalBusinessPlz,
|
||||||
|
originalBusinessEmail, originalBusinessTel
|
||||||
|
]);
|
||||||
|
|
||||||
// Save handler - save all fields at once
|
// Save handler - save all fields at once
|
||||||
const onSave = useCallback(async (): Promise<void> => {
|
const onSave = useCallback(async (): Promise<void> => {
|
||||||
if (!isModified) return;
|
if (!isModified) return;
|
||||||
|
|
||||||
|
// Validate email and phone fields before saving
|
||||||
|
if (!businessEmailValid || !businessTelValid) {
|
||||||
|
setSaveError(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setIsSaving(true);
|
setIsSaving(true);
|
||||||
setSaveError(false);
|
setSaveError(false);
|
||||||
const removeToast = toastRack.displayToast(
|
const removeToast = toastRack.displayToast(
|
||||||
@@ -177,10 +303,6 @@ const ExtendedProfileSettings: React.FC<ExtendedProfileSettingsProps> = ({ class
|
|||||||
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_SPECIALIZATION, specialization));
|
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_SPECIALIZATION, specialization));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (address !== originalAddress) {
|
|
||||||
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_ADDRESS, address));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (website !== originalWebsite) {
|
if (website !== originalWebsite) {
|
||||||
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_WEBSITE, website));
|
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_WEBSITE, website));
|
||||||
}
|
}
|
||||||
@@ -189,14 +311,51 @@ const ExtendedProfileSettings: React.FC<ExtendedProfileSettingsProps> = ({ class
|
|||||||
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_FURTHER_INFO, furtherInfo));
|
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_FURTHER_INFO, furtherInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (practiceName !== originalPracticeName) {
|
||||||
|
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_PRACTICE_NAME, practiceName));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save business contact fields if modified
|
||||||
|
if (businessStreet !== originalBusinessStreet) {
|
||||||
|
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_BUSINESS_STREET, businessStreet));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (businessStreetNr !== originalBusinessStreetNr) {
|
||||||
|
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_BUSINESS_STREET_NR, businessStreetNr));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (businessCity !== originalBusinessCity) {
|
||||||
|
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_BUSINESS_CITY, businessCity));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (businessPlz !== originalBusinessPlz) {
|
||||||
|
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_BUSINESS_PLZ, businessPlz));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (businessEmail !== originalBusinessEmail) {
|
||||||
|
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_BUSINESS_EMAIL, businessEmail));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (businessTel !== originalBusinessTel) {
|
||||||
|
savePromises.push(userProfilesStore.setExtendedProfileProperty(EXT_PROFILE_KEY_BUSINESS_TEL, businessTel));
|
||||||
|
}
|
||||||
|
|
||||||
await Promise.all(savePromises);
|
await Promise.all(savePromises);
|
||||||
|
|
||||||
// Update original values after successful save
|
// Update original values after successful save
|
||||||
setOriginalTitle(title);
|
setOriginalTitle(title);
|
||||||
setOriginalSpecialization(specialization);
|
setOriginalSpecialization(specialization);
|
||||||
setOriginalAddress(address);
|
|
||||||
setOriginalWebsite(website);
|
setOriginalWebsite(website);
|
||||||
setOriginalFurtherInfo(furtherInfo);
|
setOriginalFurtherInfo(furtherInfo);
|
||||||
|
setOriginalPracticeName(practiceName);
|
||||||
|
|
||||||
|
// Update original business contact field values
|
||||||
|
setOriginalBusinessStreet(businessStreet);
|
||||||
|
setOriginalBusinessStreetNr(businessStreetNr);
|
||||||
|
setOriginalBusinessCity(businessCity);
|
||||||
|
setOriginalBusinessPlz(businessPlz);
|
||||||
|
setOriginalBusinessEmail(businessEmail);
|
||||||
|
setOriginalBusinessTel(businessTel);
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error("Failed to save profile information", e);
|
logger.error("Failed to save profile information", e);
|
||||||
@@ -207,8 +366,11 @@ const ExtendedProfileSettings: React.FC<ExtendedProfileSettingsProps> = ({ class
|
|||||||
removeToast();
|
removeToast();
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
isModified, title, specialization, address, website, furtherInfo,
|
isModified, title, specialization, website, furtherInfo, practiceName,
|
||||||
originalTitle, originalSpecialization, originalAddress, originalWebsite, originalFurtherInfo,
|
originalTitle, originalSpecialization, originalWebsite, originalFurtherInfo, originalPracticeName,
|
||||||
|
businessStreet, businessStreetNr, businessCity, businessPlz, businessEmail, businessTel,
|
||||||
|
originalBusinessStreet, originalBusinessStreetNr, originalBusinessCity, originalBusinessPlz,
|
||||||
|
originalBusinessEmail, originalBusinessTel, businessEmailValid, businessTelValid,
|
||||||
toastRack, userProfilesStore
|
toastRack, userProfilesStore
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -248,14 +410,85 @@ const ExtendedProfileSettings: React.FC<ExtendedProfileSettingsProps> = ({ class
|
|||||||
|
|
||||||
<div className="mx_ExtendedProfileSettings_field">
|
<div className="mx_ExtendedProfileSettings_field">
|
||||||
<Field
|
<Field
|
||||||
label={_t("settings|extended_profile_settings|address")}
|
label={_t("settings|extended_profile_settings|practice_name")}
|
||||||
value={address}
|
value={practiceName}
|
||||||
onChange={onAddressChanged}
|
onChange={onPracticeNameChanged}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Street and number in one row, street takes 2/3 width */}
|
||||||
|
<div className="mx_ExtendedProfileSettings_fieldsRow mx_ExtendedProfileSettings_address_row">
|
||||||
|
<div className="mx_ExtendedProfileSettings_field mx_ExtendedProfileSettings_field_business_street">
|
||||||
|
<Field
|
||||||
|
label={_t("settings|extended_profile_settings|business_street")}
|
||||||
|
value={businessStreet}
|
||||||
|
onChange={onBusinessStreetChanged}
|
||||||
|
disabled={isSaving}
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mx_ExtendedProfileSettings_field mx_ExtendedProfileSettings_field_business_street_nr">
|
||||||
|
<Field
|
||||||
|
label={_t("settings|extended_profile_settings|business_street_nr")}
|
||||||
|
value={businessStreetNr}
|
||||||
|
onChange={onBusinessStreetNrChanged}
|
||||||
|
disabled={isSaving}
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* PLZ and City in one row, PLZ takes 1/3 width */}
|
||||||
|
<div className="mx_ExtendedProfileSettings_fieldsRow mx_ExtendedProfileSettings_postal_row">
|
||||||
|
<div className="mx_ExtendedProfileSettings_field mx_ExtendedProfileSettings_field_business_plz">
|
||||||
|
<Field
|
||||||
|
label={_t("settings|extended_profile_settings|business_plz")}
|
||||||
|
value={businessPlz}
|
||||||
|
onChange={onBusinessPlzChanged}
|
||||||
|
disabled={isSaving}
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mx_ExtendedProfileSettings_field mx_ExtendedProfileSettings_field_business_city">
|
||||||
|
<Field
|
||||||
|
label={_t("settings|extended_profile_settings|business_city")}
|
||||||
|
value={businessCity}
|
||||||
|
onChange={onBusinessCityChanged}
|
||||||
|
disabled={isSaving}
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Email field with validation */}
|
||||||
|
<div className="mx_ExtendedProfileSettings_fieldsRow mx_ExtendedProfileSettings_contact_row">
|
||||||
|
<div className="mx_ExtendedProfileSettings_field">
|
||||||
|
<Field
|
||||||
|
label={_t("settings|extended_profile_settings|business_email")}
|
||||||
|
value={businessEmail}
|
||||||
|
onChange={onBusinessEmailChanged}
|
||||||
|
disabled={isSaving}
|
||||||
|
autoComplete="off"
|
||||||
|
type="email"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Telephone field with validation */}
|
||||||
|
<div className="mx_ExtendedProfileSettings_field">
|
||||||
|
<Field
|
||||||
|
label={_t("settings|extended_profile_settings|business_tel")}
|
||||||
|
value={businessTel}
|
||||||
|
onChange={onBusinessTelChanged}
|
||||||
|
disabled={isSaving}
|
||||||
|
autoComplete="off"
|
||||||
|
type="tel"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div className="mx_ExtendedProfileSettings_field">
|
<div className="mx_ExtendedProfileSettings_field">
|
||||||
<Field
|
<Field
|
||||||
label={_t("settings|extended_profile_settings|website")}
|
label={_t("settings|extended_profile_settings|website")}
|
||||||
@@ -288,11 +521,12 @@ const ExtendedProfileSettings: React.FC<ExtendedProfileSettingsProps> = ({ class
|
|||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{saveError && (
|
{saveError && (
|
||||||
<div className="mx_ExtendedProfileSettings_error">
|
<Alert title={_t("settings|extended_profile_settings|failed_to_save")} type="critical">
|
||||||
<ErrorMessage>{_t("settings|extended_profile_settings|failed_to_save")}</ErrorMessage>
|
{businessEmailValid ? null : _t("settings|extended_profile_settings|invalid_email")}
|
||||||
</div>
|
<span> </span>
|
||||||
|
{businessTelValid ? null : _t("settings|extended_profile_settings|invalid_phone")}
|
||||||
|
</Alert>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2479,13 +2479,21 @@
|
|||||||
"additional_information": "Zusätzliche Informationen",
|
"additional_information": "Zusätzliche Informationen",
|
||||||
"professional_title": "Titel",
|
"professional_title": "Titel",
|
||||||
"specialization": "Fachgebiet",
|
"specialization": "Fachgebiet",
|
||||||
"address": "Adresse",
|
"practice_name": "Praxisname / Firmenname",
|
||||||
|
"business_street": "Strasse",
|
||||||
|
"business_street_nr": "Hausnummer",
|
||||||
|
"business_plz": "PLZ",
|
||||||
|
"business_city": "Ort",
|
||||||
|
"business_email": "Email (geschäftlich)",
|
||||||
|
"business_tel": "Telefon (geschäftlich)",
|
||||||
"website": "Webseite",
|
"website": "Webseite",
|
||||||
"further_information": "Weitere Informationen / Qualifikationen",
|
"further_information": "Weitere Informationen / Qualifikationen",
|
||||||
"saving_profile": "Profil wird gespeichert...",
|
"saving_profile": "Profil wird gespeichert...",
|
||||||
"failed_to_load": "Fehler beim Laden der erweiterten Profileinstellungen.",
|
"failed_to_load": "Fehler beim Laden der erweiterten Profileinstellungen.",
|
||||||
"failed_to_save": "Fehler beim Speichern der erweiterten Profileinstellungen.",
|
"failed_to_save": "Fehler beim Speichern der erweiterten Profileinstellungen.",
|
||||||
"server_not_supported": "Dieser Server unterstützt keine erweiterten Profileinstellungen."
|
"server_not_supported": "Dieser Server unterstützt keine erweiterten Profileinstellungen.",
|
||||||
|
"invalid_email": "Ungültige E-Mail-Adresse.",
|
||||||
|
"invalid_phone": "Ungültige Telefonnummer."
|
||||||
},
|
},
|
||||||
"account": {
|
"account": {
|
||||||
"dialog_title": "<strong>Einstellungen:</strong> Konto",
|
"dialog_title": "<strong>Einstellungen:</strong> Konto",
|
||||||
@@ -3833,7 +3841,10 @@
|
|||||||
"header": "Weitere Informationen",
|
"header": "Weitere Informationen",
|
||||||
"title": "Titel",
|
"title": "Titel",
|
||||||
"specialization": "Fachgebiet",
|
"specialization": "Fachgebiet",
|
||||||
|
"practice_name": "Praxisname / Firmenname",
|
||||||
"address": "Adresse",
|
"address": "Adresse",
|
||||||
|
"business_email": "E-Mail (geschäftlich)",
|
||||||
|
"business_tel": "Telefon (geschäftlich)",
|
||||||
"website": "Webseite",
|
"website": "Webseite",
|
||||||
"further_info": "Weitere Infos / Qualifikationen",
|
"further_info": "Weitere Infos / Qualifikationen",
|
||||||
"not_provided": "Nicht angegeben",
|
"not_provided": "Nicht angegeben",
|
||||||
|
|||||||
@@ -2507,13 +2507,21 @@
|
|||||||
"additional_information": "Additional Information",
|
"additional_information": "Additional Information",
|
||||||
"professional_title": "Title",
|
"professional_title": "Title",
|
||||||
"specialization": "Specialization",
|
"specialization": "Specialization",
|
||||||
"address": "Address",
|
"practice_name": "Practice Name",
|
||||||
|
"business_street": "Strasse",
|
||||||
|
"business_street_nr": "Street Number",
|
||||||
|
"business_plz": "ZIP Code",
|
||||||
|
"business_city": "City",
|
||||||
|
"business_email": "Business Email",
|
||||||
|
"business_tel": "Business Phone",
|
||||||
"website": "Website",
|
"website": "Website",
|
||||||
"further_information": "Further Information / Qualifications",
|
"further_information": "Further Information / Qualifications",
|
||||||
"saving_profile": "Saving profile...",
|
"saving_profile": "Saving profile...",
|
||||||
"failed_to_load": "Failed to load extended profile settings.",
|
"failed_to_load": "Failed to load extended profile settings.",
|
||||||
"failed_to_save": "Failed to save extended profile settings.",
|
"failed_to_save": "Failed to save extended profile settings.",
|
||||||
"server_not_supported": "Your server does not support extended profile settings."
|
"server_not_supported": "Your server does not support extended profile settings.",
|
||||||
|
"invalid_email": "Invalid email.",
|
||||||
|
"invalid_phone": "Invalid phone number."
|
||||||
},
|
},
|
||||||
"account": {
|
"account": {
|
||||||
"dialog_title": "<strong>Settings:</strong> Account",
|
"dialog_title": "<strong>Settings:</strong> Account",
|
||||||
@@ -3869,7 +3877,10 @@
|
|||||||
"header": "Additional infos",
|
"header": "Additional infos",
|
||||||
"title": "Title",
|
"title": "Title",
|
||||||
"specialization": "Speciality",
|
"specialization": "Speciality",
|
||||||
|
"practice_name": "Practice name",
|
||||||
"address": "Address",
|
"address": "Address",
|
||||||
|
"business_email": "Business email",
|
||||||
|
"business_tel": "Business phone",
|
||||||
"website": "Website",
|
"website": "Website",
|
||||||
"further_info": "Further infos / qualifications",
|
"further_info": "Further infos / qualifications",
|
||||||
"not_provided": "Not provided",
|
"not_provided": "Not provided",
|
||||||
|
|||||||
@@ -2505,13 +2505,21 @@
|
|||||||
"additional_information": "Informations supplémentaires",
|
"additional_information": "Informations supplémentaires",
|
||||||
"professional_title": "Titre",
|
"professional_title": "Titre",
|
||||||
"specialization": "Spécialisation",
|
"specialization": "Spécialisation",
|
||||||
"address": "Adresse",
|
"practice_name": "Nom de l’entreprise",
|
||||||
|
"business_street": "Rue",
|
||||||
|
"business_street_nr": "Numéro de rue",
|
||||||
|
"business_plz": "Code postal",
|
||||||
|
"business_city": "Ville",
|
||||||
|
"business_email": "E-mail professionnel",
|
||||||
|
"business_tel": "Téléphone professionnel",
|
||||||
"website": "Site web",
|
"website": "Site web",
|
||||||
"further_information": "Informations supplémentaires / qualifications",
|
"further_information": "Informations supplémentaires / qualifications",
|
||||||
"saving_profile": "Enregistrement des paramètres de profil étendus…",
|
"saving_profile": "Enregistrement des paramètres de profil étendus…",
|
||||||
"failed_to_load": "Erreur lors du chargement des paramètres de profil étendus.",
|
"failed_to_load": "Erreur lors du chargement des paramètres de profil étendus.",
|
||||||
"failed_to_save": "Erreur lors de l'enregistrement des paramètres de profil étendus.",
|
"failed_to_save": "Erreur lors de l'enregistrement des paramètres de profil étendus.",
|
||||||
"server_not_supported": "Le serveur d’accueil ne prend pas en charge les paramètres de profil étendus."
|
"server_not_supported": "Le serveur d’accueil ne prend pas en charge les paramètres de profil étendus.",
|
||||||
|
"invalid_email": "Adresse e-mail invalide.",
|
||||||
|
"invalid_phone": "Numéro de téléphone invalide."
|
||||||
},
|
},
|
||||||
"account": {
|
"account": {
|
||||||
"dialog_title": "<strong>Paramètres : </strong> Compte",
|
"dialog_title": "<strong>Paramètres : </strong> Compte",
|
||||||
@@ -3868,7 +3876,10 @@
|
|||||||
"header": "Informations supplémentaires",
|
"header": "Informations supplémentaires",
|
||||||
"title": "Titre",
|
"title": "Titre",
|
||||||
"specialization": "Spécialisation",
|
"specialization": "Spécialisation",
|
||||||
|
"practice_name": "Nom de l’entreprise",
|
||||||
"address": "Adresse",
|
"address": "Adresse",
|
||||||
|
"business_email": "Email (professionnel)",
|
||||||
|
"business_tel": "Téléphone (professionnel)",
|
||||||
"website": "Site web",
|
"website": "Site web",
|
||||||
"further_info": "Informations supplémentaires / qualifications",
|
"further_info": "Informations supplémentaires / qualifications",
|
||||||
"not_provided": "Non fourni",
|
"not_provided": "Non fourni",
|
||||||
|
|||||||
Reference in New Issue
Block a user