From 08da8198f8009bd84bca70c629a62c1b17e07eae Mon Sep 17 00:00:00 2001 From: Max <133934232+Kleostro@users.noreply.github.com> Date: Wed, 8 May 2024 09:52:41 +0300 Subject: [PATCH] refactor: create every inputField separately --- .../model/RegistrationFormModel.ts | 324 ++++++++---------- .../view/RegistrationFormView.ts | 253 +++++--------- .../view/registrationForm.module.scss | 157 +++------ 3 files changed, 262 insertions(+), 472 deletions(-) diff --git a/src/widgets/RegistrationForm/model/RegistrationFormModel.ts b/src/widgets/RegistrationForm/model/RegistrationFormModel.ts index 80d31d82..10886f94 100644 --- a/src/widgets/RegistrationForm/model/RegistrationFormModel.ts +++ b/src/widgets/RegistrationForm/model/RegistrationFormModel.ts @@ -1,44 +1,37 @@ import type InputFieldModel from '@/entities/InputField/model/InputFieldModel.ts'; -import type { Address, User } from '@/shared/types/user.ts'; +import type { AddressType } from '@/shared/types/address.ts'; +import type { Address, PersonalData, User, UserCredentials } from '@/shared/types/user.ts'; -import CountryChoiceModel from '@/features/CountryChoice/model/CountryChoiceModel.ts'; +import AddressModel from '@/entities/Address/model/AddressModel.ts'; import getCustomerModel, { CustomerModel } from '@/shared/API/customer/model/CustomerModel.ts'; import EventMediatorModel from '@/shared/EventMediator/model/EventMediatorModel.ts'; import LoaderModel from '@/shared/Loader/model/LoaderModel.ts'; import serverMessageModel from '@/shared/ServerMessage/model/ServerMessageModel.ts'; import getStore from '@/shared/Store/Store.ts'; -import { setCurrentUser } from '@/shared/Store/actions.ts'; +import { setBillingCountry, setCurrentUser } from '@/shared/Store/actions.ts'; import MEDIATOR_EVENT from '@/shared/constants/events.ts'; -import * as CONSTANT_FORMS from '@/shared/constants/forms.ts'; -import * as FORM_CONSTANT from '@/shared/constants/forms/register/constant.ts'; -import * as FORM_FIELDS from '@/shared/constants/forms/register/fieldParams.ts'; +import { INPUT_TYPE, PASSWORD_TEXT } from '@/shared/constants/forms.ts'; import { MESSAGE_STATUS, SERVER_MESSAGE } from '@/shared/constants/messages.ts'; import { SIZES } from '@/shared/constants/sizes.ts'; -import isKeyOfUserData from '@/shared/utils/isKeyOfUserData.ts'; +import { ADDRESS_TYPE } from '@/shared/types/address.ts'; import RegistrationFormView from '../view/RegistrationFormView.ts'; class RegisterFormModel { + private addressWrappers: Record = { + [ADDRESS_TYPE.BILLING]: new AddressModel(ADDRESS_TYPE.BILLING, { + setDefault: true, + }), + [ADDRESS_TYPE.SHIPPING]: new AddressModel(ADDRESS_TYPE.SHIPPING, { + setAsBilling: true, + setDefault: true, + }), + }; + private eventMediator = EventMediatorModel.getInstance(); private inputFields: InputFieldModel[] = []; - private isValidInputFields: Record = {}; - - private userData: User = { - addresses: [], - birthDate: '', - defaultBillingAddressId: null, - defaultShippingAddressId: null, - email: '', - firstName: '', - id: '', - lastName: '', - locale: '', - password: '', - version: 0, - }; - private view: RegistrationFormView = new RegistrationFormView(); constructor() { @@ -56,35 +49,6 @@ class RegisterFormModel { return currentUserData; } - private createBillingCountryChoice(): boolean { - return this.createCountryChoice( - FORM_FIELDS.BILLING_ADDRESS_COUNTRY.inputParams.id, - this.view.getBillingAddressWrapper(), - ); - } - - private createCountryChoice(inputFieldId: string, wrapper: HTMLElement): boolean { - const addressInput = this.view - .getInputFields() - .find((inputField) => inputField.getView().getInput().getHTML().id === inputFieldId) - ?.getView() - .getInput() - .getHTML(); - - if (addressInput) { - const countryChoiceModel = new CountryChoiceModel(addressInput); - wrapper.append(countryChoiceModel.getHTML()); - } - return true; - } - - private createShippingCountryChoice(): boolean { - return this.createCountryChoice( - FORM_FIELDS.SHIPPING_ADDRESS_COUNTRY.inputParams.id, - this.view.getShippingAddressWrapper(), - ); - } - private async editDefaultBillingAddress(addressId: string, userData: User | null): Promise { let currentUserData = userData; if (currentUserData) { @@ -107,97 +71,67 @@ class RegisterFormModel { return currentUserData; } - private getAddressData(key: string): Address { - const addressData = - key === CONSTANT_FORMS.USER_ADDRESS_TYPE.BILLING - ? this.getAddressDataHandler( - [ - FORM_FIELDS.BILLING_ADDRESS_CITY, - FORM_FIELDS.BILLING_ADDRESS_POSTAL_CODE, - FORM_FIELDS.BILLING_ADDRESS_STREET, - ], - CONSTANT_FORMS.USER_COUNTRY_ADDRESS.BILLING, - ) - : this.getAddressDataHandler( - [ - FORM_FIELDS.SHIPPING_ADDRESS_CITY, - FORM_FIELDS.SHIPPING_ADDRESS_POSTAL_CODE, - FORM_FIELDS.SHIPPING_ADDRESS_STREET, - ], - CONSTANT_FORMS.USER_COUNTRY_ADDRESS.SHIPPING, - ); - - return addressData; + private getCredentialsData(): UserCredentials { + return { + email: this.view.getEmailField().getView().getValue(), + password: this.view.getPasswordField().getView().getValue(), + }; } - private getAddressDataHandler( - [city, postalCode, street]: { inputParams: { id: string } }[], - country: string, - ): Address { - const store = getStore().getState(); - const addressData: Address = { - city: this.getAddressValue(city), - country: country === CONSTANT_FORMS.USER_COUNTRY_ADDRESS.BILLING ? store.billingCountry : store.shippingCountry, - email: this.userData.email, - firstName: this.userData.firstName, + private getFormUserData(): User { + const userData: User = { + addresses: [], + birthDate: this.view.getDateOfBirthField().getView().getValue(), + defaultBillingAddressId: null, + defaultShippingAddressId: null, + email: this.view.getEmailField().getView().getValue(), + firstName: this.view.getFirstNameField().getView().getValue(), id: '', - lastName: this.userData.lastName, - postalCode: this.getAddressValue(postalCode), - state: '', - streetName: this.getAddressValue(street), - streetNumber: '', + lastName: this.view.getLastNameField().getView().getValue(), + locale: '', + password: this.view.getPasswordField().getView().getValue(), + version: 0, }; - return addressData; - } - private getAddressValue(field: { inputParams: { id: string } }): string { - return ( - this.inputFields - .find((inputField) => inputField.getView().getInput().getHTML().id === field.inputParams.id) - ?.getView() - .getValue() || '' - ); + this.view.getSubmitFormButton().setDisabled(); + return userData; } - private getFormUserData(): User { - this.inputFields.forEach((inputField) => { - const input = inputField.getView().getInput(); - const inputHTML = input.getHTML(); - const inputValue = input.getValue(); - - const key = inputHTML.id.replace(FORM_CONSTANT.KEY, ''); - - if (isKeyOfUserData(this.userData, key)) { - this.userData[key] = inputValue; - this.isValidInputFields[inputHTML.id] = false; - input.clear(); - } - }); - - this.view.getSubmitFormButton().setDisabled(); - return this.userData; + private getPersonalData(): PersonalData { + return { + email: this.view.getEmailField().getView().getValue(), + firstName: this.view.getFirstNameField().getView().getValue(), + lastName: this.view.getLastNameField().getView().getValue(), + }; } private init(): boolean { this.inputFields = this.view.getInputFields(); + Object.values(this.addressWrappers) + .reverse() + .forEach((addressWrapper) => { + this.inputFields.push(...addressWrapper.getView().getInputFields()); + this.getHTML().append(addressWrapper.getHTML()); + }); this.inputFields.forEach((inputField) => this.setInputFieldHandlers(inputField)); this.setPreventDefaultToForm(); this.setSubmitFormHandler(); - this.createBillingCountryChoice(); - this.createShippingCountryChoice(); - const checkboxSingleAddress = this.view.getSingleAddressCheckBox().getHTML(); - checkboxSingleAddress.addEventListener('change', () => + const checkboxSingleAddress = this.addressWrappers[ADDRESS_TYPE.SHIPPING] + .getView() + .getAddressAsBillingCheckBox() + ?.getHTML(); + checkboxSingleAddress?.addEventListener('change', () => this.singleAddressCheckBoxHandler(checkboxSingleAddress.checked), ); + this.setSwitchPasswordVisibilityHandler(); return true; } private registerUser(): void { const loader = new LoaderModel(SIZES.MEDIUM).getHTML(); this.view.getSubmitFormButton().getHTML().append(loader); - this.getFormUserData(); getCustomerModel() - .registerNewCustomer(this.userData) + .registerNewCustomer(this.getFormUserData()) .then((newUserData) => { if (newUserData) { this.successfulUserRegistration(newUserData); @@ -211,16 +145,33 @@ class RegisterFormModel { } private resetInputFieldsValidation(): void { - Object.entries(this.isValidInputFields).forEach(([key]) => { - this.isValidInputFields[key] = false; - }); + const checkboxSingleAddress = this.addressWrappers[ADDRESS_TYPE.SHIPPING] + .getView() + .getAddressAsBillingCheckBox() + ?.getHTML(); + const checkboxDefaultShippingAddress = this.addressWrappers[ADDRESS_TYPE.SHIPPING] + .getView() + .getAddressByDefaultCheckBox() + ?.getHTML(); + const checkboxDefaultBillingAddress = this.addressWrappers[ADDRESS_TYPE.BILLING] + .getView() + .getAddressByDefaultCheckBox() + ?.getHTML(); + if (checkboxSingleAddress) { + checkboxSingleAddress.checked = false; + } + if (checkboxDefaultShippingAddress) { + checkboxDefaultShippingAddress.checked = false; + } + if (checkboxDefaultBillingAddress) { + checkboxDefaultBillingAddress.checked = false; + } + this.addressWrappers[ADDRESS_TYPE.BILLING].getView().switchVisibilityAddressWrapper(false); } private setInputFieldHandlers(inputField: InputFieldModel): boolean { const inputHTML = inputField.getView().getInput().getHTML(); - this.isValidInputFields[inputHTML.id] = false; inputHTML.addEventListener('input', () => { - this.isValidInputFields[inputHTML.id] = inputField.getIsValid(); this.switchSubmitFormButtonAccess(); }); return true; @@ -240,50 +191,57 @@ class RegisterFormModel { return true; } - private singleAddressCheckBoxHandler(isChecked: boolean): boolean { - const billingAddressFieldID = [ - FORM_FIELDS.BILLING_ADDRESS_COUNTRY.inputParams.id, - FORM_FIELDS.BILLING_ADDRESS_STREET.inputParams.id, - FORM_FIELDS.BILLING_ADDRESS_CITY.inputParams.id, - FORM_FIELDS.BILLING_ADDRESS_POSTAL_CODE.inputParams.id, - ]; - - this.view.switchVisibilityBillingAddressWrapper(isChecked); + private setSwitchPasswordVisibilityHandler(): boolean { + this.view.getShowPasswordElement().addEventListener('click', () => { + const input = this.view.getPasswordField().getView().getInput().getHTML(); + input.type = input.type === INPUT_TYPE.PASSWORD ? INPUT_TYPE.TEXT : INPUT_TYPE.PASSWORD; + input.placeholder = input.type === INPUT_TYPE.PASSWORD ? PASSWORD_TEXT.HIDDEN : PASSWORD_TEXT.SHOWN; + this.view.switchPasswordElementSVG(input.type); + }); + return true; + } + private singleAddressCheckBoxHandler(isChecked: boolean): boolean { if (!isChecked) { window.scrollTo({ top: document.documentElement.scrollHeight, }); } - billingAddressFieldID.forEach((id) => { - this.inputFields - .find((inputField) => inputField.getView().getInput().getHTML().id === id) - ?.getView() - .getInput() - .clear(); - this.isValidInputFields[id] = isChecked; - }); + const billingAddressView = this.addressWrappers[ADDRESS_TYPE.BILLING].getView(); + const shippingAddress = this.addressWrappers[ADDRESS_TYPE.SHIPPING]; + shippingAddress + .getView() + .getInputFields() + .forEach((inputFields) => { + const inputElement = inputFields.getView(); + const billingInput = billingAddressView + .getInputFields() + .find( + (inputField) => + inputField.getView().getInput().getHTML().placeholder === inputElement.getInput().getHTML().placeholder, + ); + if (billingInput) { + billingInput.getView().getInput().getHTML().value = inputElement.getInput().getHTML().value; + } + getStore().dispatch(setBillingCountry(getStore().getState().shippingCountry)); + }); + billingAddressView.switchVisibilityAddressWrapper(isChecked); this.switchSubmitFormButtonAccess(); return true; } private successfulUserRegistration(newUserData: User): void { - const userDataWithLogin = { - email: this.userData.email, - password: this.userData.password, - }; - this.eventMediator.notify(MEDIATOR_EVENT.USER_LOGIN, userDataWithLogin); + this.eventMediator.notify(MEDIATOR_EVENT.USER_LOGIN, this.getCredentialsData()); this.updateUserData(newUserData).catch(() => { serverMessageModel.showServerMessage(SERVER_MESSAGE.BAD_REQUEST, MESSAGE_STATUS.ERROR); }); - this.resetInputFieldsValidation(); } private switchSubmitFormButtonAccess(): boolean { - if (Object.values(this.isValidInputFields).every((value) => value)) { + if (this.inputFields.every((inputField) => inputField.getIsValid())) { this.view.getSubmitFormButton().setEnabled(); this.view.getSubmitFormButton().getHTML().focus(); } else { @@ -298,9 +256,9 @@ class RegisterFormModel { if (currentUserData) { currentUserData = await getCustomerModel().editCustomer( [ - CustomerModel.actionEditFirstName(this.userData.firstName), - CustomerModel.actionEditLastName(this.userData.lastName), - CustomerModel.actionEditDateOfBirth(this.userData.birthDate), + CustomerModel.actionEditFirstName(this.view.getFirstNameField().getView().getValue()), + CustomerModel.actionEditLastName(this.view.getLastNameField().getView().getValue()), + CustomerModel.actionEditDateOfBirth(this.view.getDateOfBirthField().getView().getValue()), ], currentUserData, ); @@ -310,59 +268,53 @@ class RegisterFormModel { } private async updateUserAddresses(userData: User | null): Promise { - const shippingAddress = this.getAddressData(CONSTANT_FORMS.USER_ADDRESS_TYPE.SHIPPING); - const billingAddress = this.getAddressData(CONSTANT_FORMS.USER_ADDRESS_TYPE.BILLING); - const checkboxSingleAddress = this.view.getSingleAddressCheckBox().getHTML(); - const checkboxDefaultShippingAddress = this.view.getCheckboxDefaultShippingAddress().getHTML(); - const checkboxDefaultBillingAddress = this.view.getCheckboxDefaultBillingAddress().getHTML(); + const { billing, shipping } = this.addressWrappers; + const personalData = this.getPersonalData(); + const checkboxSingleAddress = shipping.getView().getAddressAsBillingCheckBox()?.getHTML(); + const checkboxDefaultShippingAddress = shipping.getView().getAddressByDefaultCheckBox()?.getHTML(); + const checkboxDefaultBillingAddress = billing.getView().getAddressByDefaultCheckBox()?.getHTML(); + let currentUserData = userData; - currentUserData = await this.addAddress(shippingAddress, currentUserData); + currentUserData = await this.addAddress(shipping.getAddressData(personalData), currentUserData); + if (!currentUserData) { + return null; + } + const shippingAddressID = currentUserData.addresses[currentUserData.addresses.length - 1].id; - if (checkboxDefaultShippingAddress.checked && currentUserData) { - currentUserData = await this.editDefaultShippingAddress( - currentUserData.addresses[currentUserData.addresses.length - 1].id, - currentUserData, - ); + if (checkboxDefaultShippingAddress?.checked) { + currentUserData = await this.editDefaultShippingAddress(shippingAddressID, currentUserData); } - if (checkboxSingleAddress.checked && checkboxDefaultShippingAddress.checked) { - currentUserData = await this.addAddress(shippingAddress, currentUserData); - if (currentUserData) { - currentUserData = await this.editDefaultBillingAddress( - currentUserData.addresses[currentUserData.addresses.length - 1].id, - currentUserData, - ); - } + if (checkboxSingleAddress?.checked && checkboxDefaultShippingAddress?.checked) { + currentUserData = await this.editDefaultBillingAddress(shippingAddressID, currentUserData); return currentUserData; } - if (checkboxDefaultBillingAddress.checked) { - currentUserData = await this.addAddress(billingAddress, currentUserData); - if (currentUserData) { - currentUserData = await this.editDefaultBillingAddress( - currentUserData.addresses[currentUserData.addresses.length - 1].id, - currentUserData, - ); - } + currentUserData = await this.addAddress(billing.getAddressData(personalData), currentUserData); + if (!currentUserData) { + return null; + } + const billingAddressID = currentUserData.addresses[currentUserData.addresses.length - 1].id; + + if (checkboxDefaultBillingAddress?.checked) { + currentUserData = await this.editDefaultBillingAddress(billingAddressID, currentUserData); } return currentUserData; } - private async updateUserData(newUserData: User): Promise { + private async updateUserData(newUserData: User): Promise { let currentUserData: User | null = newUserData; currentUserData = await this.updatePersonalData(currentUserData); - if (currentUserData) { - this.userData = currentUserData; - } - currentUserData = await this.updateUserAddresses(currentUserData); - getStore().dispatch(setCurrentUser(this.userData)); - return this.userData; + getStore().dispatch(setCurrentUser(currentUserData)); + this.inputFields.forEach((inputField) => inputField.getView().getInput().clear()); + this.resetInputFieldsValidation(); + return currentUserData; } public getFirstInputField(): InputFieldModel { diff --git a/src/widgets/RegistrationForm/view/RegistrationFormView.ts b/src/widgets/RegistrationForm/view/RegistrationFormView.ts index c7edf37c..9c8e91a6 100644 --- a/src/widgets/RegistrationForm/view/RegistrationFormView.ts +++ b/src/widgets/RegistrationForm/view/RegistrationFormView.ts @@ -1,152 +1,81 @@ -import type { InputParams } from '@/shared/types/form'; - import InputFieldModel from '@/entities/InputField/model/InputFieldModel.ts'; import ButtonModel from '@/shared/Button/model/ButtonModel.ts'; import InputModel from '@/shared/Input/model/InputModel.ts'; import getStore from '@/shared/Store/Store.ts'; import { BUTTON_TEXT, BUTTON_TEXT_KEYS, BUTTON_TYPE } from '@/shared/constants/buttons.ts'; -import { FORM_TEXT, INPUT_TYPE } from '@/shared/constants/forms.ts'; +import { INPUT_TYPE } from '@/shared/constants/forms.ts'; import * as FORM_CONSTANT from '@/shared/constants/forms/register/constant.ts'; import * as FORM_FIELDS from '@/shared/constants/forms/register/fieldParams.ts'; import * as FORM_VALIDATION from '@/shared/constants/forms/register/validationParams.ts'; +import SVG_DETAILS from '@/shared/constants/svg.ts'; import createBaseElement from '@/shared/utils/createBaseElement.ts'; +import createSVGUse from '@/shared/utils/createSVGUse.ts'; import observeCurrentLanguage from '@/shared/utils/observeCurrentLanguage.ts'; import styles from './registrationForm.module.scss'; class RegistrationFormView { - private billingAddressWrapper: HTMLDivElement; - - private checkboxDefaultBillingAddress: InputModel; + private credentialsWrapper: HTMLDivElement; - private checkboxDefaultShippingAddress: InputModel; + private dateOfBirthField: InputFieldModel; - private checkboxSingleAddress: InputModel; + private emailField: InputFieldModel; - private credentialsWrapper: HTMLDivElement; + private firstNameField: InputFieldModel; private form: HTMLFormElement; private inputFields: InputFieldModel[] = []; + private lastNameField: InputFieldModel; + + private passwordField: InputFieldModel; + private personalDataWrapper: HTMLDivElement; - private shippingAddressWrapper: HTMLDivElement; + private showPasswordElement: HTMLDivElement; private submitFormButton: ButtonModel; constructor() { - this.inputFields = this.createInputFields(); + this.showPasswordElement = this.createShowPasswordElement(); + this.emailField = this.createEmailField(); + this.passwordField = this.createPasswordField(); + this.firstNameField = this.createFirstNameField(); + this.lastNameField = this.createLastNameField(); + this.dateOfBirthField = this.createDateOfBirthField(); this.credentialsWrapper = this.createCredentialsWrapper(); this.personalDataWrapper = this.createPersonalDataWrapper(); - this.checkboxSingleAddress = this.createCheckboxSingleAddress(); - this.checkboxDefaultShippingAddress = this.createCheckboxDefaultShippingAddress(); - this.shippingAddressWrapper = this.createShippingAddressWrapper(); - this.checkboxDefaultBillingAddress = this.createCheckboxDefaultBillingAddress(); - this.billingAddressWrapper = this.createBillingAddressWrapper(); this.submitFormButton = this.createSubmitFormButton(); this.form = this.createHTML(); } - private createBillingAddressWrapper(): HTMLDivElement { - const copyInputFields = this.inputFields; - const filteredInputFields = copyInputFields.filter( - (inputField) => - inputField.getView().getInput().getHTML().id === FORM_FIELDS.BILLING_ADDRESS_STREET.inputParams.id || - inputField.getView().getInput().getHTML().id === FORM_FIELDS.BILLING_ADDRESS_CITY.inputParams.id || - inputField.getView().getInput().getHTML().id === FORM_FIELDS.BILLING_ADDRESS_COUNTRY.inputParams.id || - inputField.getView().getInput().getHTML().id === FORM_FIELDS.BILLING_ADDRESS_POSTAL_CODE.inputParams.id, - ); - - this.billingAddressWrapper = this.createWrapperElement( - FORM_CONSTANT.TITLE_TEXT_KEYS.BILLING_ADDRESS, - [styles.billingAddressWrapper], - filteredInputFields, + private createCredentialsWrapper(): HTMLDivElement { + this.credentialsWrapper = this.createWrapperElement( + FORM_CONSTANT.TITLE_TEXT_KEYS.CREDENTIALS, + [styles.credentialsWrapper], + [this.emailField, this.passwordField], ); - const checkBoxLabel = createBaseElement({ - cssClasses: [styles.checkboxLabel], - tag: 'label', - }); - - const checkBoxText = createBaseElement({ - cssClasses: [styles.checkboxText], - innerContent: FORM_TEXT.DEFAULT_ADDRESS, - tag: 'span', - }); - - checkBoxLabel.append(checkBoxText, this.checkboxDefaultBillingAddress.getHTML()); - - this.billingAddressWrapper.append(checkBoxLabel); - - return this.billingAddressWrapper; - } - - private createCheckBoxLabel(innerContent: string, checkBoxElement: HTMLInputElement): HTMLLabelElement { - const checkboxLabel = createBaseElement({ - cssClasses: [styles.checkboxLabel], - tag: 'label', - }); - - const checkBoxText = createBaseElement({ - cssClasses: [styles.checkboxText], - innerContent, - tag: 'span', - }); - - checkboxLabel.append(checkBoxText, checkBoxElement); - return checkboxLabel; + return this.credentialsWrapper; } - private createCheckboxDefaultBillingAddress(): InputModel { - const checkboxParams: InputParams = { - autocomplete: FORM_FIELDS.CHECKBOX.AUTOCOMPLETE, - id: FORM_FIELDS.CHECKBOX.BILLING_ID, - placeholder: '', - type: INPUT_TYPE.CHECK_BOX, - }; - this.checkboxDefaultBillingAddress = new InputModel(checkboxParams); - return this.checkboxDefaultBillingAddress; + private createDateOfBirthField(): InputFieldModel { + this.dateOfBirthField = new InputFieldModel(FORM_FIELDS.BIRTHDAY, FORM_VALIDATION.BIRTHDAY_VALIDATE); + this.inputFields.push(this.dateOfBirthField); + return this.dateOfBirthField; } - private createCheckboxDefaultShippingAddress(): InputModel { - const checkboxParams: InputParams = { - autocomplete: FORM_FIELDS.CHECKBOX.AUTOCOMPLETE, - id: FORM_FIELDS.CHECKBOX.SHIPPING_ID, - placeholder: '', - type: INPUT_TYPE.CHECK_BOX, - }; - this.checkboxDefaultShippingAddress = new InputModel(checkboxParams); - return this.checkboxDefaultShippingAddress; + private createEmailField(): InputFieldModel { + this.emailField = new InputFieldModel(FORM_FIELDS.EMAIL, FORM_VALIDATION.EMAIL_VALIDATE); + this.inputFields.push(this.emailField); + return this.emailField; } - private createCheckboxSingleAddress(): InputModel { - const checkboxParams: InputParams = { - autocomplete: FORM_FIELDS.CHECKBOX.AUTOCOMPLETE, - id: FORM_FIELDS.CHECKBOX.SINGLE_ID, - placeholder: '', - type: INPUT_TYPE.CHECK_BOX, - }; - this.checkboxSingleAddress = new InputModel(checkboxParams); - - return this.checkboxSingleAddress; - } - - private createCredentialsWrapper(): HTMLDivElement { - const copyInputFields = this.inputFields; - const filteredInputFields = copyInputFields.filter( - (inputField) => - inputField.getView().getInput().getHTML().id === FORM_FIELDS.PASSWORD.inputParams.id || - inputField.getView().getInput().getHTML().id === FORM_FIELDS.EMAIL.inputParams.id, - ); - - this.credentialsWrapper = this.createWrapperElement( - FORM_CONSTANT.TITLE_TEXT_KEYS.CREDENTIALS, - [styles.credentialsWrapper], - filteredInputFields, - ); - - return this.credentialsWrapper; + private createFirstNameField(): InputFieldModel { + this.firstNameField = new InputFieldModel(FORM_FIELDS.FIRST_NAME, FORM_VALIDATION.FIRST_NAME_VALIDATE); + this.inputFields.push(this.firstNameField); + return this.firstNameField; } private createHTML(): HTMLFormElement { @@ -155,80 +84,45 @@ class RegistrationFormView { tag: 'form', }); - this.form.append( - this.credentialsWrapper, - this.personalDataWrapper, - this.shippingAddressWrapper, - this.billingAddressWrapper, - this.submitFormButton.getHTML(), - ); + this.form.append(this.credentialsWrapper, this.personalDataWrapper, this.submitFormButton.getHTML()); return this.form; } - private createInputFields(): InputFieldModel[] { - FORM_FIELDS.INPUT.forEach((inputFieldParams) => { - const currentValidateParams = FORM_VALIDATION.INPUT_VALIDATION.find( - (validParams) => validParams.key === inputFieldParams.inputParams.id, - ); - - if (currentValidateParams) { - const inputField = new InputFieldModel(inputFieldParams, currentValidateParams); - this.inputFields.push(inputField); - } else { - this.inputFields.push(new InputFieldModel(inputFieldParams, null)); - } - }); + private createLastNameField(): InputFieldModel { + this.lastNameField = new InputFieldModel(FORM_FIELDS.LAST_NAME, FORM_VALIDATION.LAST_NAME_VALIDATE); + this.inputFields.push(this.lastNameField); + return this.lastNameField; + } - return this.inputFields; + private createPasswordField(): InputFieldModel { + this.passwordField = new InputFieldModel(FORM_FIELDS.PASSWORD, FORM_VALIDATION.PASSWORD_VALIDATE); + this.inputFields.push(this.passwordField); + const inputElement = this.passwordField.getView().getHTML(); + if (inputElement instanceof HTMLLabelElement) { + inputElement.append(this.showPasswordElement); + } + return this.passwordField; } private createPersonalDataWrapper(): HTMLDivElement { - const copyInputFields = this.inputFields; - const filteredInputFields = copyInputFields.filter( - (inputField) => - inputField.getView().getInput().getHTML().id === FORM_FIELDS.FIRST_NAME.inputParams.id || - inputField.getView().getInput().getHTML().id === FORM_FIELDS.LAST_NAME.inputParams.id || - inputField.getView().getInput().getHTML().id === FORM_FIELDS.BIRTHDAY.inputParams.id, - ); + const currentInputFields = [this.firstNameField, this.lastNameField, this.dateOfBirthField]; this.personalDataWrapper = this.createWrapperElement( FORM_CONSTANT.TITLE_TEXT_KEYS.PERSONAL, [styles.personalDataWrapper], - filteredInputFields, + currentInputFields, ); return this.personalDataWrapper; } - private createShippingAddressWrapper(): HTMLDivElement { - const copyInputFields = this.inputFields; - const filteredInputFields = copyInputFields.filter( - (inputField) => - inputField.getView().getInput().getHTML().id === FORM_FIELDS.SHIPPING_ADDRESS_STREET.inputParams.id || - inputField.getView().getInput().getHTML().id === FORM_FIELDS.SHIPPING_ADDRESS_CITY.inputParams.id || - inputField.getView().getInput().getHTML().id === FORM_FIELDS.SHIPPING_ADDRESS_COUNTRY.inputParams.id || - inputField.getView().getInput().getHTML().id === FORM_FIELDS.SHIPPING_ADDRESS_POSTAL_CODE.inputParams.id, - ); - - this.shippingAddressWrapper = this.createWrapperElement( - FORM_CONSTANT.TITLE_TEXT_KEYS.SHIPPING_ADDRESS, - [styles.shippingAddressWrapper], - filteredInputFields, - ); - - const settingsAddressWrapper = createBaseElement({ - cssClasses: [styles.settingsAddressWrapper], + private createShowPasswordElement(): HTMLDivElement { + this.showPasswordElement = createBaseElement({ + cssClasses: [styles.showPasswordElement], tag: 'div', }); - - settingsAddressWrapper.append( - this.createCheckBoxLabel(FORM_TEXT.DEFAULT_ADDRESS, this.checkboxDefaultShippingAddress.getHTML()), - this.createCheckBoxLabel(FORM_TEXT.SINGLE_ADDRESS, this.checkboxSingleAddress.getHTML()), - ); - - this.shippingAddressWrapper.append(settingsAddressWrapper); - - return this.shippingAddressWrapper; + this.switchPasswordElementSVG(INPUT_TYPE.PASSWORD); + return this.showPasswordElement; } private createSubmitFormButton(): ButtonModel { @@ -268,6 +162,7 @@ class RegistrationFormView { inputFields.forEach((inputField) => { const inputFieldElement = inputField.getView().getHTML(); if (inputFieldElement instanceof HTMLLabelElement) { + inputFieldElement.classList.add(styles.label); wrapperElement.append(inputFieldElement); } else if (inputFieldElement instanceof InputModel) { wrapperElement.append(inputFieldElement.getHTML()); @@ -276,16 +171,16 @@ class RegistrationFormView { return wrapperElement; } - public getBillingAddressWrapper(): HTMLDivElement { - return this.billingAddressWrapper; + public getDateOfBirthField(): InputFieldModel { + return this.dateOfBirthField; } - public getCheckboxDefaultBillingAddress(): InputModel { - return this.checkboxDefaultBillingAddress; + public getEmailField(): InputFieldModel { + return this.emailField; } - public getCheckboxDefaultShippingAddress(): InputModel { - return this.checkboxDefaultShippingAddress; + public getFirstNameField(): InputFieldModel { + return this.firstNameField; } public getHTML(): HTMLFormElement { @@ -296,20 +191,28 @@ class RegistrationFormView { return this.inputFields; } - public getShippingAddressWrapper(): HTMLDivElement { - return this.shippingAddressWrapper; + public getLastNameField(): InputFieldModel { + return this.lastNameField; + } + + public getPasswordField(): InputFieldModel { + return this.passwordField; } - public getSingleAddressCheckBox(): InputModel { - return this.checkboxSingleAddress; + public getShowPasswordElement(): HTMLDivElement { + return this.showPasswordElement; } public getSubmitFormButton(): ButtonModel { return this.submitFormButton; } - public switchVisibilityBillingAddressWrapper(isVisible: boolean): void { - this.billingAddressWrapper.classList.toggle(styles.hidden, isVisible); + public switchPasswordElementSVG(type: string): SVGSVGElement { + const svg = document.createElementNS(SVG_DETAILS.SVG_URL, 'svg'); + this.showPasswordElement.innerHTML = ''; + svg.append(createSVGUse(type === INPUT_TYPE.PASSWORD ? SVG_DETAILS.CLOSE_EYE : SVG_DETAILS.OPEN_EYE)); + this.showPasswordElement.append(svg); + return svg; } } diff --git a/src/widgets/RegistrationForm/view/registrationForm.module.scss b/src/widgets/RegistrationForm/view/registrationForm.module.scss index cd0fe977..47c086d3 100644 --- a/src/widgets/RegistrationForm/view/registrationForm.module.scss +++ b/src/widgets/RegistrationForm/view/registrationForm.module.scss @@ -7,36 +7,7 @@ width: 100%; gap: var(--extra-small-offset); - .checkboxLabel { - display: flex; - flex-direction: row; - align-items: center; - justify-content: end; - cursor: pointer; - user-select: none; - gap: calc(var(--extra-small-offset) / 4); - - input { - cursor: pointer; - } - - @media (hover: hover) { - &:hover { - .checkboxText { - color: var(--steam-green-800); - } - } - } - } - - .checkboxText { - font: var(--regular-font); - letter-spacing: 1px; - color: var(--noble-gray-800); - transition: color 0.2s; - } - - label { + .label { position: relative; display: flex; flex-direction: column; @@ -44,48 +15,46 @@ letter-spacing: 1px; color: var(--noble-gray-800); gap: calc(var(--extra-small-offset) / 2); + } - button { - position: absolute; - right: 0; - top: 34px; - border-radius: var(--small-br); - padding: calc(var(--extra-small-offset) / 8); - width: 24px; - height: 24px; - background-color: transparent; - transform: translate(-12%, 0); + .showPasswordElement { + position: absolute; + right: 0; + top: 34px; + border-radius: var(--small-br); + padding: calc(var(--extra-small-offset) / 8); + width: 24px; + height: 24px; + background-color: transparent; + transform: translate(-12%, 0); + + svg { + width: 20px; + height: 20px; + stroke: var(--noble-gray-600); + transition: stroke 0.2s; + } + + &:focus { + background-color: var(--noble-gray-200); svg { - width: 20px; - height: 20px; - stroke: var(--noble-gray-600); - transition: stroke 0.2s; + stroke: var(--steam-green-800); } + } - &:focus { + @media (hover: hover) { + &:hover { background-color: var(--noble-gray-200); svg { stroke: var(--steam-green-800); } } - - @media (hover: hover) { - &:hover { - background-color: var(--noble-gray-200); - - svg { - stroke: var(--steam-green-800); - } - } - } } @media (max-width: 768px) { - button { - top: 24px; - } + top: 24px; } } @@ -140,21 +109,16 @@ } } - span { - font: var(--regular-font); - letter-spacing: 1px; - text-align: center; - color: var(--red-power-600); - } - button { display: flex; align-items: center; justify-content: center; + justify-self: center; grid-column: 2 span; grid-row: 5; border-radius: var(--small-br); padding: calc(var(--extra-small-offset) / 2) var(--small-offset); + width: max-content; max-height: 40px; font: var(--bold-font); letter-spacing: 1px; @@ -186,25 +150,34 @@ } .credentialsWrapper, -.personalDataWrapper, -.shippingAddressWrapper, -.billingAddressWrapper { +.personalDataWrapper { display: grid; grid-template-columns: repeat(2, 1fr); - border: 2px solid var(--noble-gray-200); - border-right: 0; - border-left: 0; - border-radius: var(--small-br); padding: var(--extra-small-offset); - gap: var(--extra-small-offset); + gap: calc(var(--extra-small-offset) * 1.5) var(--extra-small-offset); .title { + position: relative; + justify-self: center; grid-column: 2 span; + width: max-content; font: var(--medium-font); letter-spacing: 1px; text-align: center; color: var(--noble-gray-500); + &::after { + content: ''; + position: absolute; + left: 50%; + bottom: -10px; + border-radius: var(--medium-br); + width: 100%; + height: 2px; + background-color: var(--steam-green-800); + transform: translateX(-50%); + } + @media (max-width: 768px) { grid-column: 1 span; } @@ -226,44 +199,6 @@ grid-row: 2; } -.shippingAddressWrapper { - grid-column: 2 span; - grid-row: 3; -} - -.billingAddressWrapper { - grid-column: 2 span; - grid-row: 4; - transition: transform 0.2s; - animation: show 0.5s ease-in forwards; -} - -.hidden { - animation: hide 0.5s ease-in forwards; -} - -@keyframes hide { - 0% { - transform: scale(1); - } - - 100% { - display: none; - transform: scale(0); - } -} - -@keyframes show { - 0% { - display: grid; - transform: scale(0); - } - - 100% { - transform: scale(1); - } -} - .settingsAddressWrapper { display: flex; flex-direction: column;