Skip to content

Commit

Permalink
feat(RSS-ECOMM-3_30): implement language switch (#212)
Browse files Browse the repository at this point in the history
* feat: implement switching language on registration checkboxes

* feat: switch titles language

* feat: implement label text switching

* test: observe current language

* feat: add language choice to user messages

* fix: showPasswordElement position

* refactor: update text content in Russian

* feat: add a logo for language switch
  • Loading branch information
stardustmeg authored May 9, 2024
1 parent 5f0b5c6 commit 07c0020
Show file tree
Hide file tree
Showing 37 changed files with 394 additions and 166 deletions.
48 changes: 32 additions & 16 deletions src/entities/Address/view/AddressView.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import InputFieldModel from '@/entities/InputField/model/InputFieldModel.ts';
import InputModel from '@/shared/Input/model/InputModel.ts';
import { FORM_TEXT, INPUT_TYPE } from '@/shared/constants/forms.ts';
import { TITLE_TEXT } from '@/shared/constants/forms/register/constant.ts';
import getStore from '@/shared/Store/Store.ts';
import { FORM_TEXT, FORM_TEXT_KEYS, INPUT_TYPE } from '@/shared/constants/forms.ts';
import { TITLE_TEXT, TITLE_TEXT_KEYS } 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 { ADDRESS_TYPE, type AddressOptions, type AddressType, SINGLE_ADDRESS } from '@/shared/types/address.ts';
import createBaseElement from '@/shared/utils/createBaseElement.ts';
import observeCurrentLanguage from '@/shared/utils/observeCurrentLanguage.ts';

import styles from './addressView.module.scss';

Expand Down Expand Up @@ -54,7 +56,7 @@ class AddressView {
});
}

private createAddressAsBillingCheckbox(innerContent: string): HTMLLabelElement {
private createAddressAsBillingCheckbox(): HTMLLabelElement {
const checkboxLabel = createBaseElement({
attributes: {
for: SINGLE_ADDRESS,
Expand All @@ -65,9 +67,10 @@ class AddressView {

const checkBoxText = createBaseElement({
cssClasses: [styles.checkboxText],
innerContent,
innerContent: FORM_TEXT[getStore().getState().currentLanguage].SINGLE_ADDRESS,
tag: 'span',
});
observeCurrentLanguage(checkBoxText, FORM_TEXT, FORM_TEXT_KEYS.SINGLE_ADDRESS);

this.addressAsBillingCheckBox = new InputModel({
autocomplete: FORM_FIELDS.CHECKBOX.AUTOCOMPLETE,
Expand All @@ -81,7 +84,7 @@ class AddressView {
return checkboxLabel;
}

private createAddressByDefaultCheckbox(innerContent: string): HTMLLabelElement {
private createAddressByDefaultCheckbox(): HTMLLabelElement {
const checkboxLabel = createBaseElement({
attributes: {
for: this.addressType === ADDRESS_TYPE.SHIPPING ? ADDRESS_TYPE.SHIPPING : ADDRESS_TYPE.BILLING,
Expand All @@ -90,11 +93,22 @@ class AddressView {
tag: 'label',
});

const textContent =
this.addressType === ADDRESS_TYPE.SHIPPING
? FORM_TEXT[getStore().getState().currentLanguage].DEFAULT_SHIPPING_ADDRESS
: FORM_TEXT[getStore().getState().currentLanguage].DEFAULT_BILLING_ADDRESS;
const checkBoxText = createBaseElement({
cssClasses: [styles.checkboxText],
innerContent,
innerContent: textContent,
tag: 'span',
});
observeCurrentLanguage(
checkBoxText,
FORM_TEXT,
this.addressType === ADDRESS_TYPE.SHIPPING
? FORM_TEXT_KEYS.DEFAULT_SHIPPING_ADDRESS
: FORM_TEXT_KEYS.DEFAULT_BILLING_ADDRESS,
);

this.addressByDefaultCheckBox = new InputModel({
autocomplete: FORM_FIELDS.CHECKBOX.AUTOCOMPLETE,
Expand Down Expand Up @@ -158,16 +172,10 @@ class AddressView {
this.appendInputFields();

if (this.options.setDefault) {
this.address.append(
this.createAddressByDefaultCheckbox(
this.addressType === ADDRESS_TYPE.SHIPPING
? FORM_TEXT.DEFAULT_SHIPPING_ADDRESS
: FORM_TEXT.DEFAULT_BILLING_ADDRESS,
),
);
this.address.append(this.createAddressByDefaultCheckbox());
}
if (this.options.setAsBilling) {
this.address.append(this.createAddressAsBillingCheckbox(FORM_TEXT.SINGLE_ADDRESS));
this.address.append(this.createAddressAsBillingCheckbox());
}

return this.address;
Expand Down Expand Up @@ -210,12 +218,20 @@ class AddressView {
}

private createTitle(): HTMLHeadingElement {
return createBaseElement({
const title = createBaseElement({
cssClasses: [styles.title],
innerContent:
this.addressType === ADDRESS_TYPE.SHIPPING ? TITLE_TEXT.en.SHIPPING_ADDRESS : TITLE_TEXT.en.BILLING_ADDRESS,
this.addressType === ADDRESS_TYPE.SHIPPING
? TITLE_TEXT[getStore().getState().currentLanguage].SHIPPING_ADDRESS
: TITLE_TEXT[getStore().getState().currentLanguage].BILLING_ADDRESS,
tag: 'h3',
});
observeCurrentLanguage(
title,
TITLE_TEXT,
this.addressType === ADDRESS_TYPE.SHIPPING ? TITLE_TEXT_KEYS.SHIPPING_ADDRESS : TITLE_TEXT_KEYS.BILLING_ADDRESS,
);
return title;
}

public getAddressAsBillingCheckBox(): InputModel | null {
Expand Down
29 changes: 26 additions & 3 deletions src/entities/InputField/view/InputFieldView.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { InputFieldParams, InputParams, LabelParams } from '@/shared/types/form';

import InputModel from '@/shared/Input/model/InputModel.ts';
import getStore from '@/shared/Store/Store.ts';
import observeStore, { selectCurrentLanguage } from '@/shared/Store/observer.ts';
import createBaseElement from '@/shared/utils/createBaseElement.ts';

import styles from './inputFieldView.module.scss';
Expand All @@ -14,6 +16,8 @@ class InputFieldView {

private label: HTMLLabelElement | null = null;

private labelText: HTMLSpanElement | null = null;

constructor(params: InputFieldParams) {
this.input = this.createInput(params.inputParams);
this.inputField = this.createHTML(params);
Expand All @@ -32,7 +36,8 @@ class InputFieldView {
if (labelParams) {
this.inputField = this.createLabel(labelParams);
this.errorField = this.createErrorField();
this.label?.append(this.input.getHTML(), this.errorField);
this.labelText = this.createLabelText(labelParams);
this.label?.append(this.labelText, this.input.getHTML(), this.errorField);
} else {
this.inputField = this.input;
}
Expand All @@ -46,18 +51,36 @@ class InputFieldView {
}

private createLabel(labelParams: LabelParams): HTMLLabelElement {
const { for: htmlFor, text } = labelParams;
const { for: htmlFor } = labelParams;

this.label = createBaseElement({
attributes: {
for: htmlFor,
},
innerContent: text || '',
tag: 'label',
});

return this.label;
}

private createLabelText(labelParams: LabelParams): HTMLSpanElement {
const labelText = createBaseElement({
cssClasses: [styles.labelText],
tag: 'span',
});

const updateLabelText = (): void => {
if (labelParams?.text) {
labelText.textContent = labelParams.text[getStore().getState().currentLanguage];
}
};

updateLabelText();

observeStore(selectCurrentLanguage, updateLabelText);
return labelText;
}

public getErrorField(): HTMLSpanElement | null {
return this.errorField;
}
Expand Down
5 changes: 4 additions & 1 deletion src/entities/Navigation/model/NavigationModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ class NavigationModel {
try {
await this.router.navigateTo(route);
} catch {
serverMessageModel.showServerMessage(SERVER_MESSAGE.BAD_REQUEST, MESSAGE_STATUS.ERROR);
serverMessageModel.showServerMessage(
SERVER_MESSAGE[getStore().getState().currentLanguage].BAD_REQUEST,
MESSAGE_STATUS.ERROR,
);
}
});
});
Expand Down
9 changes: 3 additions & 6 deletions src/entities/Navigation/view/NavigationView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,12 @@ class NavigationView {
}

private createToLoginLink(): LinkModel {
const { currentLanguage } = getStore().getState();
this.toLoginLink = new LinkModel({
attrs: {
href: PAGE_ID.LOGIN_PAGE,
},
classes: [styles.link],
text: PAGE_LINK_TEXT[currentLanguage].LOGIN,
text: PAGE_LINK_TEXT[getStore().getState().currentLanguage].LOGIN,
});

observeCurrentLanguage(this.toLoginLink.getHTML(), PAGE_LINK_TEXT, PAGE_LINK_TEXT_KEYS.LOGIN);
Expand All @@ -50,13 +49,12 @@ class NavigationView {
}

private createToMainLink(): LinkModel {
const { currentLanguage } = getStore().getState();
this.toMainLink = new LinkModel({
attrs: {
href: PAGE_ID.MAIN_PAGE,
},
classes: [styles.link],
text: PAGE_LINK_TEXT[currentLanguage].MAIN,
text: PAGE_LINK_TEXT[getStore().getState().currentLanguage].MAIN,
});

observeCurrentLanguage(this.toMainLink.getHTML(), PAGE_LINK_TEXT, PAGE_LINK_TEXT_KEYS.MAIN);
Expand All @@ -66,13 +64,12 @@ class NavigationView {
}

private createToRegisterLink(): LinkModel {
const { currentLanguage } = getStore().getState();
this.toRegisterLink = new LinkModel({
attrs: {
href: PAGE_ID.REGISTRATION_PAGE,
},
classes: [styles.link],
text: PAGE_LINK_TEXT[currentLanguage].REGISTRATION,
text: PAGE_LINK_TEXT[getStore().getState().currentLanguage].REGISTRATION,
});

observeCurrentLanguage(this.toRegisterLink.getHTML(), PAGE_LINK_TEXT, PAGE_LINK_TEXT_KEYS.REGISTRATION);
Expand Down
4 changes: 1 addition & 3 deletions src/features/CountryChoice/view/CountryChoiceView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ class CountryChoiceView {
tag: 'div',
});

const { currentLanguage } = getStore().getState();

Object.entries(COUNTRIES_LIST[currentLanguage]).forEach(([countryName, countryCode]) =>
Object.entries(COUNTRIES_LIST[getStore().getState().currentLanguage]).forEach(([countryName, countryCode]) =>
this.countryDropList.append(this.createCountryItem(countryName, countryCode)),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ class InputFieldValidatorModel {
Validator.checkRequired(value, this.validParams),
Validator.checkWhitespace(value, this.validParams),
Validator.checkNotSpecialSymbols(value, this.validParams),
Validator.checkRequiredSymbols(value, this.validParams),
Validator.checkMinLength(value, this.validParams),
Validator.checkMaxLength(value, this.validParams),
Validator.checkRequiredSymbols(value, this.validParams),
Validator.checkValidMail(value, this.validParams),
Validator.checkValidAge(value, this.validParams),
Validator.checkMinAge(value, this.validParams),
Expand Down
5 changes: 3 additions & 2 deletions src/features/InputFieldValidator/validators/validators.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { InputFieldValidatorParams } from '@/shared/types/form.ts';

import getStore from '@/shared/Store/Store.ts';
import observeStore, { selectCurrentLanguage } from '@/shared/Store/observer.ts';
import COUNTRIES_LIST from '@/shared/constants/countriesList.ts';
import { USER_POSTAL_CODE } from '@/shared/constants/forms.ts';
import { ERROR_MESSAGE } from '@/shared/constants/messages.ts';
Expand Down Expand Up @@ -77,9 +78,10 @@ export const checkValidCountry = (value: string, validParams: InputFieldValidato
(countryName) => countryName.toLowerCase() === value.toLowerCase(),
)
) {
return ERROR_MESSAGE[checkInputLanguage(value)].INVALID_COUNTRY;
return ERROR_MESSAGE[getStore().getState().currentLanguage].INVALID_COUNTRY;
}
}
observeStore(selectCurrentLanguage, () => checkValidCountry(value, validParams));
return true;
};

Expand Down Expand Up @@ -110,6 +112,5 @@ export const checkWhitespace = (value: string, validParams: InputFieldValidatorP
if (validParams.notWhitespace && !validParams.notWhitespace.pattern.test(value)) {
return validParams.notWhitespace.messages[getStore().getState().currentLanguage];
}

return true;
};
15 changes: 12 additions & 3 deletions src/pages/LoginPage/model/LoginPageModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ class LoginPageModel implements Page {
await this.router.navigateTo(PAGE_ID.MAIN_PAGE);
return currentUser;
} catch (error) {
serverMessageModel.showServerMessage(SERVER_MESSAGE.BAD_REQUEST, MESSAGE_STATUS.ERROR);
serverMessageModel.showServerMessage(
SERVER_MESSAGE[getStore().getState().currentLanguage].BAD_REQUEST,
MESSAGE_STATUS.ERROR,
);
return null;
}
}
Expand All @@ -45,7 +48,10 @@ class LoginPageModel implements Page {
private init(): boolean {
getStore().dispatch(setCurrentPage(PAGE_ID.LOGIN_PAGE));
this.checkAuthUser().catch(() => {
serverMessageModel.showServerMessage(SERVER_MESSAGE.BAD_REQUEST, MESSAGE_STATUS.ERROR);
serverMessageModel.showServerMessage(
SERVER_MESSAGE[getStore().getState().currentLanguage].BAD_REQUEST,
MESSAGE_STATUS.ERROR,
);
});
this.view.getAuthWrapper().append(this.loginForm.getHTML());
this.loginForm.getFirstInputField().getView().getInput().getHTML().focus();
Expand All @@ -59,7 +65,10 @@ class LoginPageModel implements Page {
try {
await this.router.navigateTo(PAGE_ID.REGISTRATION_PAGE);
} catch (error) {
serverMessageModel.showServerMessage(SERVER_MESSAGE.BAD_REQUEST, MESSAGE_STATUS.ERROR);
serverMessageModel.showServerMessage(
SERVER_MESSAGE[getStore().getState().currentLanguage].BAD_REQUEST,
MESSAGE_STATUS.ERROR,
);
}
}

Expand Down
14 changes: 4 additions & 10 deletions src/pages/LoginPage/view/LoginPageView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,12 @@ class LoginPageView {
}

private createAuthDescription(): HTMLHeadingElement {
const { currentLanguage } = getStore().getState();
this.authDescription = createBaseElement({
cssClasses: [styles.authDescription],
innerContent: PAGE_DESCRIPTION[currentLanguage].LOGIN,
innerContent: PAGE_DESCRIPTION[getStore().getState().currentLanguage].LOGIN,
tag: 'h3',
});

observeCurrentLanguage(this.authDescription, PAGE_DESCRIPTION, PAGE_DESCRIPTION_KEYS.LOGIN);

return this.authDescription;
}

Expand Down Expand Up @@ -100,10 +97,9 @@ class LoginPageView {
}

private createLoginSpan(): HTMLSpanElement {
const { currentLanguage } = getStore().getState();
this.loginSpan = createBaseElement({
cssClasses: [styles.loginSpan],
innerContent: PAGE_LINK_TEXT[currentLanguage].LOGIN,
innerContent: PAGE_LINK_TEXT[getStore().getState().currentLanguage].LOGIN,
tag: 'span',
});

Expand All @@ -113,13 +109,12 @@ class LoginPageView {
}

private createRegisterLink(): LinkModel {
const { currentLanguage } = getStore().getState();
this.registerLink = new LinkModel({
attrs: {
href: PAGE_ID.REGISTRATION_PAGE,
},
classes: [styles.registerLink],
text: PAGE_LINK_TEXT[currentLanguage].REGISTRATION,
text: PAGE_LINK_TEXT[getStore().getState().currentLanguage].REGISTRATION,
});

observeCurrentLanguage(this.registerLink.getHTML(), PAGE_LINK_TEXT, PAGE_LINK_TEXT_KEYS.REGISTRATION);
Expand All @@ -128,10 +123,9 @@ class LoginPageView {
}

private createToRegisterPageWrapper(): HTMLSpanElement {
const { currentLanguage } = getStore().getState();
this.toRegisterPageWrapper = createBaseElement({
cssClasses: [styles.toRegisterPageWrapper],
innerContent: PAGE_ANSWER[currentLanguage].LOGIN,
innerContent: PAGE_ANSWER[getStore().getState().currentLanguage].LOGIN,
tag: 'span',
});

Expand Down
3 changes: 1 addition & 2 deletions src/pages/NotFoundPage/view/NotFoundPageView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,9 @@ class NotFoundPageView {
}

private createToMainButton(): ButtonModel {
const { currentLanguage } = getStore().getState();
this.toMainButton = new ButtonModel({
classes: [styles.toMainButton],
text: BUTTON_TEXT[currentLanguage].BACK_TO_MAIN,
text: BUTTON_TEXT[getStore().getState().currentLanguage].BACK_TO_MAIN,
});
observeCurrentLanguage(this.toMainButton.getHTML(), BUTTON_TEXT, BUTTON_TEXT_KEYS.BACK_TO_MAIN);
return this.toMainButton;
Expand Down
Loading

0 comments on commit 07c0020

Please sign in to comment.