Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import MainPageView from '@views/main/main-page';
import ProfileView from '@views/profile/profile-page';
import ProductPageView from '@views/product/product-page';
import RegistrationView from '@views/registration/registration-page';
import PasswordChangeView from '@views/change-password/change-password';

class App {
private headerView: HeaderView;
Expand All @@ -24,6 +25,7 @@ class App {
| LoginView
| ProfileView
| CatalogPageView
| PasswordChangeView
| null = null;

constructor() {
Expand Down Expand Up @@ -98,6 +100,12 @@ class App {
this.hideFooterHeader = true;
this.mainView.page = new Error404();
break;
case '#change':
if (isPageAccessable('authorized')) {
this.hideFooterHeader = false;
this.mainView.page = new PasswordChangeView();
}
break;
default:
this.hideFooterHeader = true;
this.mainView.page = new Error404();
Expand Down
32 changes: 32 additions & 0 deletions src/app/services/password.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Customer, CustomerChangePassword } from '@commercetools/platform-sdk';
import apiRoot from './api-root';

const changeCustomerPassword = (
customerId: string,
version: number,
currentPassword: string,
newPassword: string
): Promise<Customer | null> => {
const body: CustomerChangePassword = {
id: customerId,
version,
currentPassword,
newPassword,
};

return apiRoot
.customers()
.password()
.post({ body })
.execute()
.then((response) => {
// console.log('Password changed successfully:', response);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Лишние комменты

return response;
})
.catch((error) => {
// console.error('Error changing password:', error);
return error;
});
};

export default changeCustomerPassword;
250 changes: 250 additions & 0 deletions src/app/views/change-password/change-password.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
import View from '@views/view';
import { BaseComponent, IAttributes } from '@components/base-component';
import { FormComponent, IFormAttributes } from '@components/form-component';
import { InputFieldComponent } from '@components/input-field-component';
import {
ButtonComponent,
IButtonAttributes,
} from '@components/button-component';
import Router from '@utils/router';
import { showErrorMessage, showSucessMessage } from '@utils/toast-messages';
import createPasswordField from '@utils/create-password-field';
import createEmailField from '@utils/create-email-field';
import { getCustomer } from '@services/getCustomer';
import { Customer, CustomerSignin } from '@commercetools/platform-sdk';
import FormSectionView from '@views/registration/form-section';
import { IFormInputField } from '@utils/create-input-field';
import apiRoot from '@services/api-root';
import {
passwordValidator,
specialCharValidator,
} from '@utils/validators/password-validator';
import changeCustomerPassword from '@services/password';

export default class PasswordChangeView extends View {
private form = new FormComponent({});

private currentWrapper = new BaseComponent({});

private newWrapper = new BaseComponent({});

private passwordSection = new FormSectionView();

private emailField = new InputFieldComponent({}, {}, {});

private passwordField = new InputFieldComponent({}, {}, {});

private newPasswordField = new InputFieldComponent({}, {}, {});

private confirmNewPasswordField = new InputFieldComponent({}, {}, {});

private button = new ButtonComponent({});

private showPasswordButton = new ButtonComponent({});

private changePassword = new ButtonComponent({});

constructor() {
const attrs: IAttributes = {
tag: 'section',
id: 'change-section',
classList: 'row',
};
super(attrs);
this.addForm();
this.addCurrentSection();
this.getData();
this.addEmailField();
this.addPasswordField();
this.addNewPasswordField();
}

private addForm() {
const attrs: IFormAttributes = {
classList: 'col s6 offset-s3',
};
this.form = new FormComponent(attrs);
this.passwordSection = new FormSectionView(
'You can change your password here:'
);
this.appendChild(this.form);
this.form.node.appendChild(this.passwordSection.htmlElement);
}

private async getData() {
try {
const customer = JSON.parse(
localStorage.getItem('codecraftCustomer') as string
);
const customerData = await getCustomer(customer.id);
this.populateForm(customerData);
this.addConfirmPasswordButton();
this.addChangePasswordButton(customerData);
return customerData;
} catch (error) {
showErrorMessage('Error getting customer data');
return null;
}
}

private populateForm(customerData: Customer | null) {
if (customerData) {
const customer: Customer = customerData;
if (customer.email !== undefined) {
this.emailField.input.value = customer.email;
} else {
showErrorMessage('Email is undefined');
}
} else {
showErrorMessage('Error getting customer data');
}
}

private addCurrentSection() {
const currentWrapperAttr: IAttributes = {
tag: 'section',
classList: 'row col s12',
};
this.currentWrapper = new BaseComponent(currentWrapperAttr);
this.form.appendChild(this.currentWrapper);
}

public addEmailField() {
this.emailField = createEmailField();
this.emailField.input.setDisable(true);
this.currentWrapper.appendChild(this.emailField);
}

public addPasswordField() {
const updatedAttrs: IFormInputField = {
id: 'currentPassword',
label: 'Current password',
placeholder: 'Enter current password',
type: 'password',
customValidators: [],
};
this.passwordField = createPasswordField(updatedAttrs);
this.currentWrapper.appendChild(this.passwordField);
}

public addConfirmPasswordButton() {
const attrs: IButtonAttributes = {
type: 'button',
content: 'Confirm current password',
onClick: () => {
const email = this.emailField.getValue();
const password = this.passwordField.getValue();
this.authenticateCustomer(email, password);
},
};
this.button = new ButtonComponent(attrs);
this.button.addClass('col');
this.button.addClass('s6');
this.currentWrapper.appendChild(this.button);

const toggleButtonAttrs: IButtonAttributes = {
content: 'Show/Hide Password',
onClick: (event) => {
if (event) {
event.preventDefault();
}
this.passwordField.togglePasswordVisibility();
this.newPasswordField.togglePasswordVisibility();
this.confirmNewPasswordField.togglePasswordVisibility();
},
};

this.showPasswordButton = new ButtonComponent(toggleButtonAttrs);
this.showPasswordButton.addClass('show-hide');
this.form.appendChild(this.showPasswordButton);
}

async authenticateCustomer(email: string, password: string) {
const signInBody: CustomerSignin = {
email,
password,
};

try {
const signInResult = await apiRoot
.login()
.post({ body: signInBody })
.execute();
const customerData = signInResult.body.customer;
showSucessMessage('Valid password');
this.addNewSection();
this.addNewPasswordField();
this.addChangePasswordButton(customerData);
return signInResult;
} catch (error) {
showErrorMessage('Invalid password');
throw error;
}
}

private addNewSection() {
const newWrapperAttr: IAttributes = {
tag: 'section',
classList: 'row col s12',
};
this.newWrapper = new BaseComponent(newWrapperAttr);
this.form.appendChild(this.newWrapper);
}

public addNewPasswordField() {
const newPasswordAttrs: IFormInputField = {
id: 'new-password',
label: 'Enter new password',
placeholder: 'New password',
type: 'password',
customValidators: [passwordValidator, specialCharValidator],
};
this.newPasswordField = createPasswordField(newPasswordAttrs);
this.newWrapper.appendChild(this.newPasswordField);

const confirmNewPasswordAttrs: IFormInputField = {
id: 'confirm-new',
label: 'Enter new password again',
placeholder: 'New password',
type: 'password',
customValidators: [passwordValidator, specialCharValidator],
};
this.confirmNewPasswordField = createPasswordField(confirmNewPasswordAttrs);
this.newWrapper.appendChild(this.confirmNewPasswordField);
}

public addChangePasswordButton(customerData: Customer | null) {
const attrs: IButtonAttributes = {
type: 'button',
content: 'Save new password',
onClick: () => this.handlePasswordChange(customerData),
};

this.changePassword = new ButtonComponent(attrs);
this.changePassword.addClass('col');
this.changePassword.addClass('s6');
this.newWrapper.appendChild(this.changePassword);
}

private handlePasswordChange(customerData: Customer | null) {
const currentPassword = this.passwordField.getValue().trim();
const newPassword = this.newPasswordField.getValue().trim();
const confirmedPassword = this.confirmNewPasswordField.getValue().trim();
if (customerData && newPassword === confirmedPassword) {
changeCustomerPassword(
customerData.id,
customerData.version,
currentPassword,
newPassword
)
.then(() => PasswordChangeView.successChange())
.catch(() => showErrorMessage('Passwords do not match'));
}
}

static successChange() {
const SUCSESS_MSG = 'The password has been changed';
Router.navigateTo('#profile');
showSucessMessage(SUCSESS_MSG);
}
}
Loading