Skip to content

Commit

Permalink
feat(RSS-ECOMM-3_00): implement changes for sprint-2 (#222)
Browse files Browse the repository at this point in the history
* docs(RSS-ECOMM-2_37): Update pipeline scripts and CD for a new sprint (#199)

* docs: update the PR template

* chore: add a job to generate PR titles

* chore: remove unnecessary paths from configs

* chore: remove unused package

* chore: remove a job from CI

* refactor(RSS-ECOMM-3_27): remove redundancies (#202)

* refactor: remove redundant tag constant

* refactor: replace redundant event names

* feat(RSS-ECOMM-3_03): add filters (#201)

* feat: add size product count request

* feat: add filter, edit sort, edit get product request

* feat: add search options

* refactor(RSS-ECOMM-2_53): registration form (#204)

* refactor: separate validators into separate functions

* refactor: separate address logic into Address component

* refactor: change getIsValid method

* fix: replace type for authCustomer method

* refactor: separate disabling into ButtonView

* fix: pattern for validate

* feat: types for Address component

* feat: create messageTemplate

* refactor: create every inputField separately

* refactor: create every inputField separately

* fix: header styles

* fix(RSS-ECOMM-2_54): visualisation forms (#206)

* fix: layout registration form

* fix: layout login form

* fix: layout address

* fix: layout countryChoice

* fix: layout login and registration pages

* refactor: remove the mandatory field symbol from field signatures in forms

* feat: add formatted text function

* fix: remove formatting from fields that should not be formatted

* feat: formatting of address fields

* refactor(RSS-ECOMM-2_55): router component (#207)

* refactor: rewrite Router component

* fix: navigation links

* fix: choosing country

* refactor: country lang choice based on input

* refactor: visual layout of pages

* fix: update store

* refactor: remove redundant code

* fix: styles

* feat: add init method for App component

* Apply suggestions from code review

Co-authored-by: Meg G. <[email protected]>

---------

Co-authored-by: Meg G. <[email protected]>

* feat(RSS-ECOMM-2_99): edit api client (#209)

feat: add save token, add auth and anonym client

* feat(RSS-ECOMM-3_29): pages lazy loading (#210)

* feat: implement lazy loading for pages

* fix: add a catch block

* feat(RSS-ECOMM-3_30): implement language switch (#212)

* 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

* fix(RSS-ECOMM-3_31): rerouting to main (#213)

fix: rerouting to main

* feat(RSS-ECOMM-3_25): create pages components (#214)

* feat: add base page components

* docs: update PR template

* fix: link styles

* fix: button naming

* Apply suggestions from code review

Co-authored-by: Max <[email protected]>

---------

Co-authored-by: Max <[email protected]>

* feat(RSS-ECOMM-3_19): implement routing for all pages (#215)

feat: implement routing for all pages

* feat(RSS-ECOMM-3_21): implement navigation (#217)

* feat: implement navigation to catalog and cart pages

* fix: footer styles

* fix: header styles

* feat: implement navigation to other pages

* feat: check auth user to profile page

* feat: check auth user with init app

* feat: visually profile button

* feat(RSS-ECOMM-3_34): add catalog component (#218)

feat: add catalog component

* feat(RSS-ECOMM-3_33):  implement burger menu (#221)

feat: implement burger menu

---------

Co-authored-by: Yuliya Kursevich <[email protected]>
Co-authored-by: Max <[email protected]>
  • Loading branch information
3 people authored May 10, 2024
1 parent 55e2cff commit c4c30ff
Show file tree
Hide file tree
Showing 112 changed files with 2,225 additions and 1,087 deletions.
7 changes: 3 additions & 4 deletions .env
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@

VITE_APP_CTP_PROJECT_KEY=green-shop
VITE_APP_CTP_CLIENT_SECRET=wzD7hatuZ8giFcGL5h6htyGtNlAl1chR
VITE_APP_CTP_CLIENT_ID=LG1VRj2-lAjAdT3Wa0m9AXou
VITE_APP_CTP_CLIENT_SECRET=Nlpz1PodM9gnmEPEwHw91jhXv77qU4ww
VITE_APP_CTP_CLIENT_ID=BPJMQ0wyC-4dA_1sd04SlJQx
VITE_APP_CTP_REGION=europe-west1
VITE_APP_CTP_AUTH_URL=https://auth.europe-west1.gcp.commercetools.com
VITE_APP_CTP_API_URL=https://api.europe-west1.gcp.commercetools.com
VITE_APP_CTP_SCOPES=manage_orders:green-shop manage_payments:green-shop manage_types:green-shop view_shopping_lists:green-shop manage_customers:green-shop manage_my_orders:green-shop view_orders:green-shop manage_quotes:green-shop view_discount_codes:green-shop view_quote_requests:green-shop manage_order_edits:green-shop manage_products:green-shop manage_quote_requests:green-shop view_quotes:green-shop view_api_clients:green-shop view_order_edits:green-shop manage_shipping_methods:green-shop manage_cart_discounts:green-shop manage_my_shopping_lists:green-shop view_products:green-shop view_categories:green-shop manage_my_payments:green-shop manage_my_profile:green-shop manage_discount_codes:green-shop manage_categories:green-shop manage_shopping_lists:green-shop manage_extensions:green-shop
VITE_APP_CTP_SCOPES=manage_products:green-shop manage_sessions:green-shop manage_my_quotes:green-shop manage_customer_groups:green-shop manage_payments:green-shop manage_checkout_payment_intents:green-shop manage_api_clients:green-shop manage_order_edits:green-shop manage_project:green-shop manage_orders:green-shop create_anonymous_token:green-shop manage_business_units:green-shop manage_associate_roles:green-shop manage_product_selections:green-shop view_api_clients:green-shop view_audit_log:green-shop manage_cart_discounts:green-shop manage_my_shopping_lists:green-shop manage_connectors:green-shop manage_customers:green-shop introspect_oauth_tokens:green-shop manage_my_orders:green-shop manage_my_payments:green-shop manage_my_profile:green-shop manage_connectors_deployments:green-shop manage_audit_log:green-shop manage_attribute_groups:green-shop manage_my_quote_requests:green-shop manage_discount_codes:green-shop manage_categories:green-shop manage_extensions:green-shop manage_my_business_units:green-shop manage_import_containers:green-shop
VITE_APP_DEFAULT_SEGMENT='/'
VITE_APP_NEXT_SEGMENT=1
VITE_APP_PATH_SEGMENTS_TO_KEEP=0
Expand Down
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
- [ ] sprint and issue number (e.g. `RSS-ECOMM-3_01`, where `3` - is the sprint number and `01` - is the issue number)
- [ ] short description

👀 Example: `feat(RSS-ECOMM-2_01): description`
👀 Example: `feat(RSS-ECOMM-3_01): description`

## PR Description 🧙‍♂️

Expand Down
3 changes: 2 additions & 1 deletion .validate-branch-namerc.cjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
pattern: /^(feat|fix|hotfix|chore|refactor|revert|docs|style|test|)\(RSS-ECOMM-\d{1}_\d{2}\)\/[a-z]+[a-zA-Z0-9]*$/,
pattern:
/^sprint-3|^(feat|fix|hotfix|chore|refactor|revert|docs|style|test|)\(RSS-ECOMM-\d{1}_\d{2}\)\/[a-z]+[a-zA-Z0-9]*$/,
errorMsg: 'Please use correct branch name',
};

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@
"@commercetools/sdk-client-v2": "^2.5.0",
"@commercetools/sdk-middleware-auth": "^7.0.1",
"@commercetools/sdk-middleware-http": "^7.0.4",
"@types/js-cookie": "^3.0.6",
"autoprefixer": "^10.4.19",
"isomorphic-fetch": "^3.0.0",
"js-cookie": "^3.0.5",
"materialize-css": "^1.0.0-rc.2",
"modern-normalize": "^2.0.0",
"postcode-validator": "^3.8.20",
Expand Down
95 changes: 70 additions & 25 deletions src/app/App/model/AppModel.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
/* eslint-disable max-lines-per-function */
import type { Page } from '@/shared/types/common.ts';

import RouterModel from '@/app/Router/model/RouterModel.ts';
import LoginPageModel from '@/pages/LoginPage/model/LoginPageModel.ts';
import MainPageModel from '@/pages/MainPage/model/MainPageModel.ts';
import NotFoundPageModel from '@/pages/NotFoundPage/model/NotFoundPageModel.ts';
import RegistrationPageModel from '@/pages/RegistrationPage/model/RegistrationPageModel.ts';
import { PAGE_ID } from '@/shared/constants/pages.ts';
import FooterModel from '@/widgets/Footer/model/FooterModel.ts';
import HeaderModel from '@/widgets/Header/model/HeaderModel.ts';
Expand All @@ -17,31 +14,79 @@ class AppModel {
private router = new RouterModel();

constructor() {
this.router.setPages(this.initPages());
this.initialize()
.then()
.catch(() => {
throw new Error('AppModel initialization error');
});
}

private initPages(): Map<string, Page> {
const root = this.getHTML();
root.append(new HeaderModel(this.router).getHTML());
const loginPage = new LoginPageModel(root, this.router);
const mainPage = new MainPageModel(root, this.router);
const registrationPage = new RegistrationPageModel(root, this.router);
const notFoundPage = new NotFoundPageModel(root, this.router);
const pages: Map<string, Page> = new Map(
Object.entries({
[PAGE_ID.DEFAULT_PAGE]: mainPage,
[PAGE_ID.LOGIN_PAGE]: loginPage,
[PAGE_ID.MAIN_PAGE]: mainPage,
[PAGE_ID.NOT_FOUND_PAGE]: notFoundPage,
[PAGE_ID.REGISTRATION_PAGE]: registrationPage,
}),
);
root.append(new FooterModel(this.router).getHTML());
return pages;
private createRoutes(): Promise<Map<string, () => Promise<Page>>> {
const routesMap = {
[PAGE_ID.ABOUT_US_PAGE]: async (): Promise<Page> => {
const { default: AboutUsPageModel } = await import('@/pages/AboutUsPage/model/AboutUsPageModel.ts');
return new AboutUsPageModel(this.appView.getHTML());
},
[PAGE_ID.CART_PAGE]: async (): Promise<Page> => {
const { default: CartPageModel } = await import('@/pages/CartPage/model/CartPageModel.ts');
return new CartPageModel(this.appView.getHTML());
},
[PAGE_ID.CATALOG_PAGE]: async (): Promise<Page> => {
const { default: CatalogPageModel } = await import('@/pages/CatalogPage/model/CatalogPageModel.ts');
return new CatalogPageModel(this.appView.getHTML());
},
[PAGE_ID.DEFAULT_PAGE]: async (): Promise<Page> => {
const { default: MainPageModel } = await import('@/pages/MainPage/model/MainPageModel.ts');
return new MainPageModel(this.appView.getHTML(), this.router);
},
[PAGE_ID.ITEM_PAGE]: async (): Promise<Page> => {
const { default: ItemPageModel } = await import('@/pages/ItemPage/model/ItemPageModel.ts');
return new ItemPageModel(this.appView.getHTML());
},
[PAGE_ID.LOGIN_PAGE]: async (): Promise<Page> => {
const { default: LoginPageModel } = await import('@/pages/LoginPage/model/LoginPageModel.ts');
return new LoginPageModel(this.appView.getHTML(), this.router);
},
[PAGE_ID.MAIN_PAGE]: async (): Promise<Page> => {
const { default: MainPageModel } = await import('@/pages/MainPage/model/MainPageModel.ts');
return new MainPageModel(this.appView.getHTML(), this.router);
},
[PAGE_ID.NOT_FOUND_PAGE]: async (): Promise<Page> => {
const { default: NotFoundPageModel } = await import('@/pages/NotFoundPage/model/NotFoundPageModel.ts');
return new NotFoundPageModel(this.appView.getHTML(), this.router);
},
[PAGE_ID.REGISTRATION_PAGE]: async (): Promise<Page> => {
const { default: RegistrationPageModel } = await import(
'@/pages/RegistrationPage/model/RegistrationPageModel.ts'
);
return new RegistrationPageModel(this.appView.getHTML(), this.router);
},
[PAGE_ID.USER_PROFILE_PAGE]: async (): Promise<Page> => {
const { default: UserProfilePageModel } = await import('@/pages/UserProfilePage/model/UserProfilePageModel.ts');
return new UserProfilePageModel(this.appView.getHTML());
},
};

const routes = new Map<string, () => Promise<Page>>();
Object.entries(routesMap).forEach(([key, value]) => routes.set(key, value));

return Promise.resolve(routes);
}

private async initialize(): Promise<void> {
document.body.append(this.appView.getHTML());
this.appView.getHTML().insertAdjacentElement('beforebegin', new HeaderModel(this.router).getHTML());
this.appView.getHTML().insertAdjacentElement('afterend', new FooterModel(this.router).getHTML());

const routes = await this.createRoutes();
this.router.setRoutes(routes);
}

public getHTML(): HTMLDivElement {
return this.appView.getHTML();
public start(): boolean {
if (!this.appView.getHTML()) {
return false;
}
return true;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/app/App/tests/App.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import AppModel from '../model/AppModel.ts';
const app = new AppModel();

describe('Checking AppModel class', () => {
it('the getHTML method should return HTMLDivElement', () => {
expect(app.getHTML()).toBeInstanceOf(HTMLDivElement);
it('application successfully created', () => {
expect(app.start()).toBe(true);
});
});
5 changes: 3 additions & 2 deletions src/app/App/view/appView.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
position: relative;
display: flex;
flex-direction: column;
justify-content: space-between;
justify-content: center;
margin: 0 auto;
padding: 60px 0;
width: 100%;
min-height: 100vh;
min-height: calc(100vh - 141px);
max-width: 1440px;
}
57 changes: 24 additions & 33 deletions src/app/Router/model/RouterModel.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import type { Page } from '@/shared/types/common.ts';

import EventMediatorModel from '@/shared/EventMediator/model/EventMediatorModel.ts';
import MEDIATOR_EVENT from '@/shared/constants/events.ts';
import { PAGE_ID } from '@/shared/constants/pages.ts';

const DEFAULT_SEGMENT = import.meta.env.VITE_APP_DEFAULT_SEGMENT;
Expand All @@ -10,53 +8,46 @@ const PATH_SEGMENTS_TO_KEEP = import.meta.env.VITE_APP_PATH_SEGMENTS_TO_KEEP;
const PROJECT_TITLE = import.meta.env.VITE_APP_PROJECT_TITLE;

class RouterModel {
private eventMediator = EventMediatorModel.getInstance();

private pages: Map<string, Page> = new Map();
private routes: Map<string, () => Promise<Page>> = new Map();

constructor() {
document.addEventListener('DOMContentLoaded', () => {
document.addEventListener('DOMContentLoaded', async () => {
const currentPath = window.location.pathname
.split(DEFAULT_SEGMENT)
.slice(PATH_SEGMENTS_TO_KEEP + NEXT_SEGMENT)
.join(DEFAULT_SEGMENT);
this.handleRequest(currentPath);
await this.navigateTo(currentPath);
});
}

private handleRequest(path: string): null | string {
const pathParts = path.split(DEFAULT_SEGMENT);
const hasRoute = this.pages.has(pathParts.join(''));
if (!hasRoute) {
document.title = `${PROJECT_TITLE} | ${PAGE_ID.NOT_FOUND_PAGE}`;
this.eventMediator.notify(MEDIATOR_EVENT.CHANGE_PAGE, PAGE_ID.NOT_FOUND_PAGE);
return null;
}
document.title = `${PROJECT_TITLE} | ${pathParts.join('')}`;
this.eventMediator.notify(MEDIATOR_EVENT.CHANGE_PAGE, pathParts.join(''));
return pathParts.join('');
private changeAppTitle(path: string, hasRoute: boolean): void {
const title = `${PROJECT_TITLE} | ${hasRoute ? path : PAGE_ID.NOT_FOUND_PAGE}`;
document.title = title;
}

public navigateTo(route: string): History {
if (this.pages.has(route)) {
const pathnameApp = window.location.pathname
.split(DEFAULT_SEGMENT)
.slice(NEXT_SEGMENT, PATH_SEGMENTS_TO_KEEP + NEXT_SEGMENT)
.join(DEFAULT_SEGMENT);
const url = `${pathnameApp}/${route}`;
const titleRoute = route === '' ? PAGE_ID.MAIN_PAGE : route;
document.title = `${PROJECT_TITLE} | ${titleRoute}`;
public async navigateTo(path: string): Promise<void> {
const pathnameApp = window.location.pathname
.split(DEFAULT_SEGMENT)
.slice(NEXT_SEGMENT, PATH_SEGMENTS_TO_KEEP + NEXT_SEGMENT)
.join(DEFAULT_SEGMENT);
const url = `${pathnameApp}/${path}`;
history.pushState(path, '', url);

history.pushState(route, '', url);
const pathParts = url.split(DEFAULT_SEGMENT);
const hasRoute = this.routes.has(pathParts[1]);
this.changeAppTitle(pathParts[1], hasRoute);

this.eventMediator.notify(MEDIATOR_EVENT.CHANGE_PAGE, route);
if (!hasRoute) {
await this.routes.get(PAGE_ID.NOT_FOUND_PAGE)?.();
return;
}
return window.history;

await this.routes.get(pathParts[1])?.();
}

public setPages(pages: Map<string, Page>): Map<string, Page> {
this.pages = pages;
return this.pages;
public setRoutes(routes: Map<string, () => Promise<Page>>): Map<string, () => Promise<Page>> {
this.routes = routes;
return this.routes;
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/app/styles/common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
html,
body {
display: flex;
flex-direction: column;
align-items: center;
margin: 0 auto;
width: 100%;
min-width: 320px;
Expand Down
2 changes: 2 additions & 0 deletions src/app/styles/variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
--noble-gray-700: #727272;
--noble-gray-800: #3d3d3d;
--red-power-600: #d0302f;
--steam-green-300: #46a35880;
--steam-green-400: #c8f4b4;
--steam-green-500: #b6f09c;
--steam-green-700: #70d27a;
Expand All @@ -47,5 +48,6 @@
--small-br: 5px;
--medium-br: 5px;
--large-br: 10px;
--regular-font: 400 10px 'Cerapro', sans-serif;
}
}
5 changes: 3 additions & 2 deletions src/entities/Address/model/AddressModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Address, PersonalData } from '@/shared/types/user.ts';
import CountryChoiceModel from '@/features/CountryChoice/model/CountryChoiceModel.ts';
import getStore from '@/shared/Store/Store.ts';
import { ADDRESS_TYPE, type AddressOptions, type AddressType } from '@/shared/types/address.ts';
import formattedText from '@/shared/utils/formattedText.ts';

import AddressView from '../view/AddressView.ts';

Expand All @@ -25,15 +26,15 @@ class AddressModel {
public getAddressData(personalData: PersonalData): Address {
const store = getStore().getState();
const addressData: Address = {
city: this.view.getCityField().getView().getValue(),
city: formattedText(this.view.getCityField().getView().getValue()),
country: this.addressType === ADDRESS_TYPE.BILLING ? store.billingCountry : store.shippingCountry,
email: personalData.email,
firstName: personalData.firstName,
id: '',
lastName: personalData.lastName,
postalCode: this.view.getPostalCodeField().getView().getValue(),
state: '',
streetName: this.view.getStreetField().getView().getValue(),
streetName: formattedText(this.view.getStreetField().getView().getValue()),
streetNumber: '',
};
return addressData;
Expand Down
Loading

0 comments on commit c4c30ff

Please sign in to comment.