|
|
<template> <div class="editPersonalInfo xl:tw-max-w-[1246px] xl:tw-mx-auto"> <div class="xl:tw-flex xl:tw-justify-between xl:tw-items-start"> <userSidebar :userData="userData" :firstName="firstName" :lastName="lastName" class="tw-hidden xl:tw-block"> </userSidebar> <div class="tw-bg-white xl:tw-p-[30px] xl:tw-rounded-[20px] xl:tw-min-w-[900px] xl:tw-max-w-[900px]"> <div class="tw-text-[20px] tw-font-bold tw-text-base-primary tw-mb-[20px] md:t24 md:tw-mb-[30px]"> <two-dots class="tw-mr-[30px]"></two-dots>{{ $t("userProfile.editPersonalInfo") }} </div> <!-- alert --> <div v-if="successUpdate" class="tw-flex tw-w-full tw-right-auto tw-left-auto"> <div type="success" class="tw-absolute tw-top-0 tw-right-0 tw-left-0 tw-mx-auto tw-flex tw-flex-row tw-w-fit tw-items-center tw-bg-success-background tw-rounded-[12px] tw-px-[12px] tw-py-[10px]"> <img src="~/assets/svg/alert_success.svg" class="tw-w-[16px] tw-mr-[10px] md:tw-w-[20px]" alt="" /> <div class="tw-hidden md:tw-block tw-text-success-default tw-font-bold tw-text-[16px] md:tw-mr-[16px]"> Awesome! </div> <div class="tw-text-[12px] tw-text-success-default tw-mr-[9px] md:tw-text-[16px] md:tw-mr-[16px]"> Successfully updated. </div> <img src="~/assets/svg/alert_close.svg" @click="successUpdate = !successUpdate" /> </div> </div> <div v-if="fileTooBig" class="tw-flex tw-w-full tw-right-auto tw-left-auto"> <div type="error" class="tw-absolute tw-top-0 tw-right-0 tw-left-0 tw-mx-auto tw-flex tw-flex-row tw-w-fit tw-items-center tw-bg-error-background tw-rounded-[16px] tw-px-[12px] tw-py-[10px] tw-text-[12px]"> <img src="~/assets/svg/alert_notice.svg" class="tw-w-[16px] tw-mr-[10px] md:tw-w-[20px]" alt="" /> <div class="tw-hidden md:tw-block tw-text-error-default tw-mr-[25px] tw-text-[16px]"> Oops! </div>
<div class="tw-text-error-default tw-mr-[8px] md:tw-text-[16px] md:tw-mr-[16px]"> Please upload an image under 2MB. </div> <img src="~/assets/svg/alert_close_red.svg" @click="fileTooBig = !fileTooBig" alt="" /> </div> </div> <!-- user picture --> <div class="tw-flex tw-items-center tw-mb-[30px]"> <div> <img v-if="userData.MemberPicture" :src="userData.MemberPicture" class="tw-border tw-border-solid tw-border-neutral-300 tw-h-[64px] tw-w-[64px] tw-rounded-[50px] tw-mr-[15px] md:tw-h-[90px] md:tw-w-[90px] md:tw-mr-[30px]" alt="" /> <div v-else class="tw-flex tw-justify-center tw-items-center tw-bg-primary-1 tw-text-white tw-text-[32px] tw-h-[64px] tw-w-[64px] tw-rounded-[50px] tw-mr-[15px] md:tw-h-[90px] md:tw-w-[90px] md:tw-mr-[30px]"> {{ lastName.split("")[0] || "" }} </div> </div> <div> <button class="tw-border tw-border-solid tw-border-primary-1 tw-text-[14px] tw-text-primary-1 tw-px-[16px] tw-py-[9px] tw-rounded-[12px] md:tw-text-[16px]" @click="handleUploadEvent"> {{ $t("userProfile.uploadPicture") }} </button> <input type="file" class="d-none" ref="uploader" @change="getNewPicture($event)" /> <!-- <input type="file" class="d-none" ref="uploader" @change="userPictureUpload" /> --> </div> </div> <!-- form --> <form class="tw-grid tw-grid-cols-1 tw-gap-y-[20px] tw-mb-[58px] md:tw-grid-cols-2 md:tw-gap-x-[60px] md:tw-mb-[50px]"> <!-- tilte --> <div class="element md:tw-col-span-2 md:tw-max-w-[394px]"> <div class="tw-text-[14px] tw-text-base-primary tw-mb-[10px]"> {{ $t("userProfile.Title") }} </div> <elementSelectWithIndex :select="{ id: 'Title', label: 'Title', required: false, }" :yearList="genderOptions" :default="userData.Title" :value="genderOptions[0]" :validation="validation.Title" @change="userData.Title = $event"></elementSelectWithIndex> </div> <!-- firstName --> <div class="element"> <elementInput :input="{ id: 'FirstName', label: 'First Name', required: true, type: 'text', }" :default="userData.FirstName" :validation="validation.FirstName" @change="userData.FirstName = $event"></elementInput> </div> <!-- lastName --> <div class="element"> <elementInput :input="{ id: 'LastName', label: 'Last Name', required: true, type: 'text', }" :default="userData.LastName" :validation="validation.LastName" @change="userData.LastName = $event"> </elementInput> </div> <!-- email --> <div class="element"> <elementInput :input="{ id: 'Email', label: 'userProfile.personalMail', required: true, type: 'email', }" :default="userData.Email" :validation="validation.Email" @change="userData.Email = $event"> </elementInput> </div> <!-- Phone --> <div> <div class="tw-text-[14px] tw-text-base-primary tw-mb-[10px]"> {{ $t("userProfile.phone") }} </div> <div class="tw-grid tw-grid-cols-[120px_auto] tw-gap-[5px]"> <elementCountryCodeSelect :select="{ required: true, }" :userCodeSelect="codeSelect" :validation="validation.codeSelect" @returnCode = "getReturnCode"></elementCountryCodeSelect> <vue-phone-number-input v-model="userData.Phone" :validation="validation.PhoneNo" color="#E5e5e5" error-color="#ef5a5a" valid-color="#e5e5e5" :error="error" :border-radius="5" no-flags :no-country-selector="true" no-example @update="getPhoneData" :translations="translateOption"> </vue-phone-number-input> </div> </div> <!-- Birthday --> <div class="md:tw-col-span-2 xl:tw-col-span-1"> <div class="tw-text-[14px] tw-text-base-primary tw-mb-[10px]"> {{ $t("userProfile.birthday") }}<span class="tw-text-error-default">*</span> </div> <div class="tw-grid tw-grid-cols-3 tw-gap-[20px]"> <div class="element"> <elementSelectWithIndex :select="{ id: 'yearSelect', required: true, }" :yearList="yearOptions" :default="yearSelect" :validation="validation.yearSelect" @change="yearSelect = $event"></elementSelectWithIndex> </div> <div class="element"> <elementSelectWithIndex :select="{ id: 'monthSelect', required: false, }" :yearList="monthOptions" :default="monthSelect" :validation="validation.monthSelect" @change="monthSelect = $event"></elementSelectWithIndex> </div> <div class="element"> <elementSelectWithIndex :select="{ id: 'daySelect', required: false, }" :yearList="dayOptions" :default="daySelect" :validation="validation.daySelect" @change="daySelect = $event"></elementSelectWithIndex> </div> </div> </div> <!-- Country --> <div class="element md:tw-col-span-2 xl:tw-col-span-1"> <elementSelect :select="{ id: 'Country', label: 'userProfile.countryAndRegion', required: true, }" :selectList="countryOptions" :default="userData.CountryID" :validation="validation.CountryID" @change="userData.CountryID = $event"></elementSelect> </div> <!-- language --> <v-spacer class="tw-items-center md:tw-flex md:tw-justify-start md:tw-mt-[20px] md:tw-flex-nowrap"> <div class="tw-inline-block tw-mb-[20px] md:tw-whitespace-nowrap md:tw-mb-0"> {{ $t("userProfile.preferLanguage") }} </div> <v-spacer class="tw-flex md:tw-w-fit md:tw-ml-[30px]"> <v-checkbox v-model="languageSelect.en" class="mt-0" hide-details :label="$t('English')"></v-checkbox> <v-checkbox v-model="languageSelect.zhtw" class="ms-10 mt-0" hide-details :label="$t('Chinese')"> </v-checkbox> </v-spacer> </v-spacer> </form> <!-- button --> <div> <button class="tw-text-[18px] tw-bg-primary-1 tw-text-white tw-py-[12px] tw-w-full tw-rounded-[16px] tw-mb-[10px] md:tw-w-fit md:tw-px-[16px] md:tw-mr-[20px]" @click="patchUserData()"> {{ $t("userProfile.saveButton") }} </button> <button class="tw-text-[18px] tw-bg-white tw-text-primary-1 tw-py-[12px] tw-w-full tw-rounded-[16px] md:tw-w-fit md:tw-px-[16px] xl:tw-hidden"> {{ $t("Cancel") }} </button> </div> </div> </div> <CropImageDialog :isCropImageDialogActive="isCropImageDialogActive" :cropImagePreview="cropImagePreview" @close-crop-dialog="closeCropDialog" @upload-image-success="userPictureUpload"></CropImageDialog> <loading :isLoading="isPageLoading"></loading> </div> </template> <script> import elementSelect from "@/components/newComponent/form/ElementSelect.vue"; import elementInput from "@/components/newComponent/form/ElementInput.vue"; import SavedExhibitions from "../../components/user/savedExhibitions.vue"; import SavedExhibitionsDialog from "../../components/user/savedExhibitionsDialog.vue"; import CropImageDialog from "../../components/user/cropImageDialog.vue"; import TwoDots from "@/components/TwoDots"; import userSidebar from "@/components/user/userSidebar.vue"; import elementSelectWithIndex from "@/components/newComponent/form/ElementSelectWithIndex.vue"; import elementCountryCodeSelect from "@/components/newComponent/form/ElementCountryCodeSelect.vue"; import loading from "@/components/newComponent/loading/loading.vue";
import is from "is_js"; export default { name: "editPersonalInfo", layout: "profile", components: { elementSelect, elementInput, SavedExhibitions, SavedExhibitionsDialog, CropImageDialog, TwoDots, userSidebar, elementSelectWithIndex, is, elementCountryCodeSelect, loading, }, data() { return { countryList: [], genderOptions: ["Mr.", "Ms."], successUpdate: false, fileTooBig: false, firstName: "", lastName: "", countryCode: "", userData: {}, yearOptions: [], monthOptions: [], dayOptions: [], countryOptions: [], yearSelect: "", monthSelect: "", daySelect: "", languageSelect: { en: "", zhtw: "", }, isCropImageDialogActive: false, cropImagePreview: "", translateOption: { countrySelectorLabel: this.$t("country code"), phoneNumberLabel: this.$t("phone number"), }, rules: { require: (value) => !!value || this.$t("Required."), email: (v) => /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/.test( v ) || this.$t("Invalid email"), checkPassword: (v) => (/(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])/.test(v) && v.length >= 8 && v.length <= 20) || this.$t( "Passwords must be 8-20 characters with at least 1 number, 1 lower case letter and 1 upper case letter" ), }, phoneValid: false, validation: { Title: true, FirstName: true, LastName: true, Email: true, yearSelect: true, monthSelect: true, daySelect: true, CountryID: true, codeSelect: true, PhoneNo: true, }, errors: null, userPic: {}, payload:[], dialCode:"", test:[], codeSelect: "", error: false, isPageLoading: false, value: "0", }; }, created() { this.isPageLoading = true; this.fetchCountry(); this.$store.dispatch("updatePicture"); this.fetchUserData(); this.$nextTick(()=>{ this.isPageLoading = false; }); }, mounted() { this.yearOptions = Array.from(new Array(103), (val, index) => (index + 1920).toString() ); this.monthOptions = Array.from(new Array(13), (val, index) => { if (index < 10 && index > 0) { return "0" + index.toString(); } if (index >= 10) { return index.toString(); } }); this.dayOptions = Array.from(new Array(32), (val, index) => { if (index < 10 && index > 0) { return "0" + index.toString(); } if (index >= 10) { return index.toString(); } }); this.$nextTick(() => { window.addEventListener("resize", this.onResize); }); }, methods: { getReturnCode(code){ this.userData.PhoneCode = code; },
getPhoneData(phoneData) { this.countryCode = phoneData.countryCode; //this.userData.PhoneCode = phoneData.countryCallingCode;
this.phoneValid = phoneData.isValid; },
//Save Member Info
patchUserData() { this.validators(); if(this.validators()){
if(this.$vuetify.breakpoint.name !== "xs"){ this.userData.BirthDate = this.yearSelect + "-" + this.monthSelect + "-" + this.daySelect; if(this.userData.BirthDate.length < 10){ this.userData.BirthDate = null; } } if(this.languageSelect.en == true){ this.userData.LanguageID = "en-US";
}else if(this.languageSelect.zhtw == true){ this.userData.LanguageID = "zh-TW";
}else{ this.userData.LanguageID = "null";
} const patchData = JSON.parse(JSON.stringify(this.userData));
this.$axios .post( `/trending/api/Members/Member`, patchData ) .then((response) => { //console.log(JSON.stringify(response));
if (response.status == 200) { this.$notify({ type: "success", text: "更新成功", }); } this.fetchUserData(); this.$auth.$storage.setUniversal("userPicture", patchData.MemberPicture); this.$store.dispatch("updatePicture"); }) .catch((error) => { console.log(error); }); } },
//Get Member Info
fetchUserData() { this.$axios .get( `/trending/api/Members/Info` ) .then((response) => { //console.log(response);
if(response && response.data && response.data.DATA && response.data.DATA.rel){ let data = response.data.DATA.rel if(data){ this.userData = data;
if(this.userData.CountryID == null){ this.userData.CountryID = "0"; } if(this.userData.Title == null){ this.userData.Title = "0"; } if(this.userData.PhoneCode == null){ this.userData.PhoneCode = "0"; } if(this.userData.BirthDate == null){ this.yearSelect = "0"; this.monthSelect = "0"; this.daySelect = "0"; }
this.firstName = this.userData.FirstName; this.lastName = this.userData.LastName; //this.userData.Phone ? (this.phoneValid = true): (this.phoneValid = false);
this.codeSelect = this.userData.PhoneCode; if(this.userData.LanguageID == "en-US"){ this.languageSelect.en = true;
}else if(this.userData.LanguageID == "zh-TW"){ this.languageSelect.zhtw = true;
}else{ this.languageSelect.en = ""; this.languageSelect.zhtw = "";
}
if ( this.userData.BirthDate && typeof this.userData.BirthDate === "object"
){ this.yearSelect = ""; this.monthSelect = ""; this.daySelect = "";
}else{ const space = this.userData.BirthDate.split("T"); const date = space[0].split("-"); this.yearSelect = date[0]; this.monthSelect = date[1]; this.daySelect = date[2];
} } } }) .catch((error) => { console.log(error); }); },
handleUploadEvent() { window.addEventListener("focus", () => { }, { once: true }); this.$refs.uploader.click();
},
//
getNewPicture(e) { this.payload = new FormData(); this.payload.append("file", e.target.files[0]); const path = URL.createObjectURL(e.target.files[0]); this.cropImagePreview = path ; this.isCropImageDialogActive = !this.isCropImageDialogActive; },
userPictureUpload(e) { //const fileSize = (e.target.files[0].size / 1024 / 1024).toFixed(1);
this.$axios .post( `/trending/api/Members/UploadAvatar`, this.payload ) .then((response) => { //console.log(JSON.stringify(response))
if(response && response.data){
this.isCropImageDialogActive = !this.isCropImageDialogActive; this.fetchUserData(); this.$notify({ type: "success", text: "更新成功", }); } }) .catch((error) => { console.log(error); }); }, fetchCountry() { this.$axios .get(`/trending/api/location/countries?RegionID&Lang=${this.$i18n.localeProperties["langQuery"]}`) .then((response) => { //console.log(JSON.stringify(response));
if(response && response.data && response.data.DATA && response.data.DATA.rel){ let data = response.data.DATA.rel if(data){ this.countryList = data; this.countryOptions = this.countryList.map((item) => { return { id: item.CountryID, name: item.CountryENName + " " + item.CountryName, }; });
} } }) .catch((error) => { console.log(error); }); }, closeCropDialog() { this.isCropImageDialogActive = !this.isCropImageDialogActive; }, handleImageUpdate() { this.fetchUserData(); //this.patchUserData();
this.closeCropDialog(); }, validators() { if (is.empty(this.userData.FirstName)) { this.validation.FirstName = false; } else { this.validation.FirstName = true; } if (is.empty(this.userData.LastName)) { this.validation.LastName = false; } else { this.validation.LastName = true; } if (is.empty(this.userData.Email) || is.not.email(this.userData.Email)) { this.validation.Email = false; } else { this.validation.Email = true; } if (is.empty(this.yearSelect)) { this.validation.yearSelect = false; } else { this.validation.yearSelect = true; } if (is.empty(this.monthSelect)) { this.validation.monthSelect = false; } else { this.validation.monthSelect = true; } if (is.empty(this.daySelect)) { this.validation.daySelect = false; } else { this.validation.daySelect = true; } if (is.null(this.userData.CountryID) || this.userData.CountryID == 0) { this.validation.CountryID = false; } else { this.validation.CountryID = true; } if(this.userData.PhoneCode == "999"){ this.validation.codeSelect = false;
}else{ this.validation.codeSelect = true;
} if (this.userData.Phone == null ) { this.validation.PhoneNo = false; this.error = true; } else { this.validation.PhoneNo = true; this.error = false; } this.errors = Object.entries(this.validation).filter( (e) => e[1] == false ); if (this.errors.length > 0) { return false; } else { return true; } }, }, }; </script>
<style scoped lang="scss" scoped> select { background-image: url("~/assets/svg/dropdownarrow.svg"); width: auto; height: auto; background-position: right 12px center; background-repeat: no-repeat; }
.success-alert { position: absolute; left: 13%; z-index: 10; top: -3%; }
.success-alert-dialog { position: absolute; left: 13%; z-index: 10; top: 3%; }
:deep() { .input-tel__input { height: 44px; border: 1px solid #e5e5e5; }
}
</style>
|