Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release Candidate - v5.0.0 #429

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0885580
fix: switch to playlist_multiselect
olga-jwp Nov 14, 2023
0e92a58
Merge pull request #398 from jwplayer/OWA-38-add-multiselect-to-hub-s…
olga-jwp Nov 15, 2023
b3aa739
feat(user): add ability to add password to a social account
naumovski-filip Nov 15, 2023
18afd04
Merge pull request #392 from jwplayer/social-providers-password
AntonLantukh Nov 15, 2023
6b1285b
feat(project): services modularization (#363)
AntonLantukh Nov 16, 2023
8518460
fix(project): change variable name (#402)
AntonLantukh Nov 16, 2023
621e9e7
feat(payment): generate billing receipt (#401)
kiremitrov123 Nov 17, 2023
5e2ce14
fix(user): missing isCommon error check (#403)
kiremitrov123 Nov 17, 2023
a932ba1
chore: merge release to develop
dbudzins Nov 27, 2023
42d0320
chore: merge release to develop
dbudzins Nov 28, 2023
b3adc70
chore: merge release to develop
dbudzins Nov 28, 2023
190bd06
chore: update action
dbudzins Nov 30, 2023
924f4b6
chore: fix action
dbudzins Nov 30, 2023
230c59b
chore: merge branch 'release' into develop
dbudzins Nov 30, 2023
65ea840
fix(e2e): fix cleeng test (#414)
AntonLantukh Dec 5, 2023
547775e
feat(project): modularization docs (#413)
AntonLantukh Dec 5, 2023
c47ca66
fix(series): add empty media items filter (#415)
AntonLantukh Dec 8, 2023
de4ff48
fix(home): parse the scheduled date (#417)
AntonLantukh Dec 8, 2023
111fcfb
fix(series): fix 'hasMore' param (#416)
AntonLantukh Dec 8, 2023
527ca02
fix: add truthy param check to evaluation of urlSigning enabled (#422)
dbudzins Jan 9, 2024
2aec0dd
feat(project): use xml for ad config (#421)
AntonLantukh Jan 9, 2024
ca9d905
fix(project): fix error state for preview and demo modes (#423)
AntonLantukh Jan 10, 2024
016fd4e
feat(project): update changelog generation package (#426)
AntonLantukh Jan 10, 2024
dda841a
feat(project): empty commit for services and controllers modularization.
AntonLantukh Jan 10, 2024
6c84c05
chore(release): v5.0.0
invalid-email-address Jan 10, 2024
e2b37ef
fix(project): pre-release fixes
AntonLantukh Jan 11, 2024
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
21 changes: 11 additions & 10 deletions .depcheckrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ ignores: [
'\#types',
'\#components',
'\#utils',
# This is used in src/styles, which recognizes absolute paths from the repo root
'src',
# To support e2e-reports
'allure-commandline',
'src', # This is used in src/styles, which recognizes absolute paths from the repo root
'allure-commandline', # To support e2e-reports
'@codeceptjs/allure-legacy',
# For extracting i18next translation keys
'i18next-parser',
# To run linting checks
'npm-run-all',
# SW code is injected at build time
'virtual:pwa-register',
'faker',
'i18next-parser', # For extracting i18next translation keys
'npm-run-all', # To run linting checks
'virtual:pwa-register', # Service Worker code is injected at build time
'vite-plugin-pwa/client', # Used to generate pwa framework
'reflect-metadata', # Used for ioc resolution
'@babel/plugin-proposal-decorators', # Used to build with decorators for ioc resolution
'babel-plugin-transform-typescript-metadata', # Used to build with decorators for ioc resolution
'@babel/core', # Required peer dependency for babel plugins above
]
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,21 @@ jobs:

- name: Generate changelog
id: changelog
uses: TriPSs/conventional-changelog-action@v4.1.1
uses: TriPSs/conventional-changelog-action@v5.1.0
with:
github-token: ${{ secrets.ACTION_TOKEN }}
release-count: 0
skip-tag: true
git-push: false
skip-ci: false
preset: conventionalcommits
input-file: "CHANGELOG.md"
input-file: 'CHANGELOG.md'

- name: Create Pull Request
uses: peter-evans/create-pull-request@v5
with:
token: ${{ secrets.ACTION_TOKEN }}
title: Release Candidate - ${{ steps.changelog.outputs.tag }}${{ github.ref_name != 'develop' && ' (Hotfix)' || ''}}
title: Release Candidate - ${{ steps.changelog.outputs.tag }}${{ github.ref_name != 'develop' && ' (Hotfix)' || ''}}
base: release
branch: ${{ github.ref_name == 'develop' && 'release-candidate' || 'hotfix-release-candidate' }}
body: ${{ steps.changelog.outputs.clean_changelog }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/release-merge-back.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
uses: devmasx/merge-branch@master
with:
type: now
from_branch: release
target_branch: develop
message: 'chore: merge release to develop'
github_token: ${{ secrets.ACTION_TOKEN }}
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,33 @@
## [5.0.0](https://github.com/jwplayer/ott-web-app/compare/v4.31.1...v5.0.0) (2024-01-10)


### ⚠ BREAKING CHANGES

* **project:** services and controllers modularization

### Features

* **payment:** generate billing receipt ([#401](https://github.com/jwplayer/ott-web-app/issues/401)) ([621e9e7](https://github.com/jwplayer/ott-web-app/commit/621e9e741530ced0be1739527f5da0b62c303384))
* **project:** empty commit for services and controllers modularization. ([dda841a](https://github.com/jwplayer/ott-web-app/commit/dda841a92f7696a90f145e2c2d7ee77fdec6b6a3))
* **project:** modularization docs ([#413](https://github.com/jwplayer/ott-web-app/issues/413)) ([547775e](https://github.com/jwplayer/ott-web-app/commit/547775e68a47d5915677b1ed2ab76c90f5f6ca2e))
* **project:** services modularization ([#363](https://github.com/jwplayer/ott-web-app/issues/363)) ([6b1285b](https://github.com/jwplayer/ott-web-app/commit/6b1285b6f703e8a6de04b1ad9d7f3a2bb77897a9))
* **project:** update changelog generation package ([#426](https://github.com/jwplayer/ott-web-app/issues/426)) ([016fd4e](https://github.com/jwplayer/ott-web-app/commit/016fd4e775fbe95df291a9257430b31e1e0e5bd7))
* **project:** use xml for ad config ([#421](https://github.com/jwplayer/ott-web-app/issues/421)) ([2aec0dd](https://github.com/jwplayer/ott-web-app/commit/2aec0dde9a7624d28494720ca0164f925e983384))
* **user:** add ability to add password to a social account ([b3aa739](https://github.com/jwplayer/ott-web-app/commit/b3aa7394131227aa2713a5951c6047f2ae7be804))


### Bug Fixes

* add truthy param check to evaluation of urlSigning enabled ([#422](https://github.com/jwplayer/ott-web-app/issues/422)) ([527ca02](https://github.com/jwplayer/ott-web-app/commit/527ca02088ba62765db442af66c5bfe6c14b573a))
* **e2e:** fix cleeng test ([#414](https://github.com/jwplayer/ott-web-app/issues/414)) ([65ea840](https://github.com/jwplayer/ott-web-app/commit/65ea840449444ad0e5652aad76e27db5fa5fe54f))
* **home:** parse the scheduled date ([#417](https://github.com/jwplayer/ott-web-app/issues/417)) ([de4ff48](https://github.com/jwplayer/ott-web-app/commit/de4ff48019835ea0bbeaa8641ef8bfafb7107bad))
* **project:** change variable name ([#402](https://github.com/jwplayer/ott-web-app/issues/402)) ([8518460](https://github.com/jwplayer/ott-web-app/commit/85184608dc387675ed73274c56dedac5d57fc8f3))
* **project:** fix error state for preview and demo modes ([#423](https://github.com/jwplayer/ott-web-app/issues/423)) ([ca9d905](https://github.com/jwplayer/ott-web-app/commit/ca9d905a8af4c49811fb65085520d4a98b9a54af))
* **series:** add empty media items filter ([#415](https://github.com/jwplayer/ott-web-app/issues/415)) ([c47ca66](https://github.com/jwplayer/ott-web-app/commit/c47ca66bfb1d757597555ee8d6c7e5373b9a7a70))
* **series:** fix 'hasMore' param ([#416](https://github.com/jwplayer/ott-web-app/issues/416)) ([111fcfb](https://github.com/jwplayer/ott-web-app/commit/111fcfb548ee162b7e04930626a0c089f88ebcb7))
* switch to playlist_multiselect ([0885580](https://github.com/jwplayer/ott-web-app/commit/08855805a9292eda3704094e0e9c196132b40738))
* **user:** missing isCommon error check ([#403](https://github.com/jwplayer/ott-web-app/issues/403)) ([5e2ce14](https://github.com/jwplayer/ott-web-app/commit/5e2ce144ca8b1920df460178632d8448f3226d8a))

## [4.31.1](https://github.com/jwplayer/ott-web-app/compare/v4.31.0...v4.31.1) (2023-11-28)


Expand Down
87 changes: 87 additions & 0 deletions docs/modularization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Architecture

In order to implement a more structural approach of organizing the code and to reduce coupling we decided to add Dependency Injection (DI) and Inversion of Control (IOC) patterns support for services and controllers present in the application. We expect these patterns to be even more effective when working with different OTT platforms where JS code can be reused.

## DI library

InversifyJS is used to provide IOC container and to perform DI for both services and controllers. Injection happens automatically with the help of the reflect-metadata package (by adding `injectable` decorators).

> **Important:** The type of the service / controller defined in the constructor should be used as a value, without the `type` keyword.

Won't work:

```
import type {CleengService} from './cleeng.service';

@injectable()
export default class CleengAccountService extends AccountService {
private readonly cleengService: CleengService;

constructor(cleengService: CleengService) {
...
}
}
```

Will work:

```
import CleengService from './cleeng.service';

@injectable()
export default class CleengAccountService extends AccountService {
private readonly cleengService: CleengService;

constructor(cleengService: CleengService) {
...
}
}
```

This is the price we need to pay to remove `inject` decorators from the constructor to avoid boilerplate code.

## Initialization

We use [register](src/modules/register.ts) function to initialize services and controllers. Some services don't depend on any integration provider (like `ConfigService` or `EpgService`), while such services as `CleengAccountService` or `InplayerAccountService` depend on the provider and get injected into controllers conditionally based on the `INTEGRATION_TYPE` dynamic value (`JWP` or `CLEENG`).

Initialization starts in the [index.tsx](src/index.tsx) file where we register services. We do it outside of the react component to make services available in different parts of the application.

The app is loaded in the [useBootstrapApp](src/hooks/useBootstrapApp.ts) hook with the help of the `AppController` which is responsible for retrieving data from the Config and Settings services, initializing the initial state of the application and hitting init methods of the base app's controllers.

## Controllers and Services

Both Controllers and Services are defined as classes. We use `injectable` decorator to make them visible for the InversifyJS library.

> **Important:** Use arrow functions for class methods to avoid lost context.

### Services

Business logic should be mostly stored in Services. We use services to communicate with the back-end and to process the data we receive.

Services also help to manage different dependencies. For example, we can use them to support several integration providers. If this is the case we should also create a common interface and make dependant entities use the interface instead of the actual implementation. This is how inversion of control principle can be respected. Then when we inject services into controllers, we use interface types instead of the implementation classes.

All in all:

- Services contain the actual business logic;
- They can be injected into controllers (which orchestrate different services) or into other services;
- We should avoid using services in the View part of the application and prefer controllers instead. However, it is still possible to do in case controllers fully duplicate service's methods (EPG service). In this case we can use a react hook (for the web app) and get access to the service there.
- One service can use provides different implementations. For example, we can split it into Cleeng and JWP implementation (account, checkout and so on).

> **Important:** Services should be written in an environment / client agnostic way (i.e. no Window usage) to be reused on different platforms (Web, SmartTV and so on).

### Controllers

Controllers bind different parts of the application. Controllers use services, store and provide methods to operate with business logic in the UI and in the App. If we need to share code across controllers then it is better to promote the code to the next level (we do it in the AppController). Then it is possible to modify both controllers to call the same (now shared) code.

- They can be called from the View part of the application;
- They use the data from the Store and from the UI to operate different injected services;
- They use the Store to persist the entities when needed;
- They return data back to the UI when needed.

> **Important:** We should try to avoid controllers calling each other because it leads to circular dependencies and makes the code messy. However now they do it sometimes (to be refactored).

### Controllers / Services retrieval

To get access to the service / controller [getModule](src/modules/container.ts) utility can be used. It also accepts a `required` param which can be used in case the presence of the service is optional. If `required` is provided but service itself is not bound then the error will be thrown.

`getNamedModule` function is mostly use in controllers to retrieve integration-specific services, like AccountService or CheckoutService.
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jw-ott-webapp",
"version": "4.31.1",
"version": "5.0.0",
"main": "index.js",
"repository": "https://github.com/jwplayer/ott-web-app.git",
"author": "JW Player",
Expand Down Expand Up @@ -43,14 +43,15 @@
"dependencies": {
"@adyen/adyen-web": "^5.42.1",
"@codeceptjs/allure-legacy": "^1.0.2",
"@inplayer-org/inplayer.js": "^3.13.21",
"@inplayer-org/inplayer.js": "^3.13.24",
"classnames": "^2.3.1",
"date-fns": "^2.28.0",
"dompurify": "^2.3.8",
"i18next": "^22.4.15",
"i18next-browser-languagedetector": "^6.1.1",
"i18next-http-backend": "^2.2.0",
"ini": "^3.0.1",
"inversify": "^6.0.1",
"jwt-decode": "^3.1.2",
"lodash.merge": "^4.6.2",
"marked": "^4.1.1",
Expand All @@ -63,11 +64,14 @@
"react-infinite-scroller": "^1.2.6",
"react-query": "^3.39.0",
"react-router-dom": "^6.4.0",
"reflect-metadata": "^0.1.13",
"wicg-inert": "^3.1.1",
"yup": "^0.32.9",
"zustand": "^3.6.9"
},
"devDependencies": {
"@babel/core": "^7.22.11",
"@babel/plugin-proposal-decorators": "^7.22.10",
"@codeceptjs/configure": "^0.8.0",
"@commitlint/cli": "^12.1.1",
"@commitlint/config-conventional": "^12.1.1",
Expand All @@ -90,6 +94,7 @@
"@vitejs/plugin-react": "^4.0.4",
"@vitest/coverage-v8": "^0.33.0",
"allure-commandline": "^2.17.2",
"babel-plugin-transform-typescript-metadata": "^0.3.2",
"codeceptjs": "3.5.5",
"confusing-browser-globals": "^1.0.10",
"csv-parse": "^5.4.0",
Expand Down
2 changes: 0 additions & 2 deletions public/locales/en/error.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
{
"check_your_config": "There was a problem retrieving the application configuration. Try again later. If the problem persists contact technical support.",
"check_your_settings": "There was a problem loading the default settings. Try again later. If the problem persists contact technical support.",
"config_invalid": "Invalid or missing config",
"generic_error_description": "Try refreshing this page or come back later.",
"generic_error_heading": "There was an issue loading the application",
"learn_more": "Learn more",
"notfound_error_description": "This page doesn't exist.",
"notfound_error_heading": "Not found",
"playlist_not_found": "Playlist not found",
"settings_invalid": "Invalid or missing settings",
"video_not_found": "Video not found"
}
10 changes: 10 additions & 0 deletions public/locales/en/user.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"account": {
"about_you": "Profile info",
"add_password": "Add password",
"add_password_error": "Failed to proceed to the Add Password screen. Please try again.",
"add_password_modal_text": "We sent instructions to {{email}} on how to add a password. If you don’t receive the email within a few minutes, check your spam folder or",
"add_profile": "Add profile",
"cancel": "Cancel",
"confirm_password": "Confirm password",
Expand All @@ -20,6 +23,10 @@
},
"title": "Delete account"
},
"delete_account_password_warning": {
"text": "To delete your account when using social media account(s) for sign-in, you will first need to add an account password and then initiate the deletion process again.",
"title": "Warning"
},
"edit_account": "Edit account",
"edit_information": "Edit information",
"edit_password": "Edit password",
Expand All @@ -44,6 +51,9 @@
"manage_profiles": "Manage profiles",
"other_registration_details": "Other registration details",
"password": "Password",
"proceed_to_adding_a_password": "Proceed to adding a password",
"resend_mail": "resend the email.",
"resend_mail_error": "An error occurred while resending the email. Please try again.",
"save": "Save",
"security": "Password",
"terms_and_tracking": "Legal & Marketing",
Expand Down
2 changes: 0 additions & 2 deletions public/locales/es/error.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
{
"check_your_config": "Hubo un problema al recuperar la configuración de la aplicación. Inténtalo de nuevo más tarde. Si el problema persiste, contacta al soporte técnico.",
"check_your_settings": "Hubo un problema al cargar los ajustes predeterminados. Inténtalo de nuevo más tarde. Si el problema persiste, contacta al soporte técnico.",
"config_invalid": "Configuración inválida o faltante",
"generic_error_description": "Intenta actualizar esta página o vuelve más tarde.",
"generic_error_heading": "Hubo un problema al cargar la aplicación",
"learn_more": "Más información",
"notfound_error_description": "Esta página no existe.",
"notfound_error_heading": "No encontrado",
"playlist_not_found": "Lista de reproducción no encontrada",
"settings_invalid": "Ajustes inválidos o faltantes",
"video_not_found": "Video no encontrado"
}
10 changes: 10 additions & 0 deletions public/locales/es/user.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"account": {
"about_you": "Información de perfil",
"add_password": "Agregar contraseña",
"add_password_error": "No se pudo pasar a la pantalla Agregar contraseña. Inténtalo de nuevo.",
"add_password_modal_text": "Enviamos instrucciones a {{email}} sobre cómo agregar una contraseña. Si no recibes el correo electrónico en unos minutos, revisa tu carpeta de spam o",
"add_profile": "Añadir perfil",
"cancel": "Cancelar",
"confirm_password": "Confirmar contraseña",
Expand All @@ -20,6 +23,10 @@
},
"title": "Borrar cuenta"
},
"delete_account_password_warning": {
"text": "Para eliminar su cuenta cuando utiliza cuentas de redes sociales para iniciar sesión, primero deberá agregar una contraseña de cuenta y luego iniciar el proceso de eliminación nuevamente.",
"title": "Advertencia"
},
"edit_account": "Editar cuenta",
"edit_information": "Editar información",
"edit_password": "Editar contraseña",
Expand All @@ -44,6 +51,9 @@
"manage_profiles": "Administrar perfiles",
"other_registration_details": "Otros detalles de registro",
"password": "Contraseña",
"proceed_to_adding_a_password": "Proceda a agregar una contraseña",
"resend_mail": "reenvíe el correo electrónico.",
"resend_mail_error": "Se produjo un error al reenviar el correo electrónico. Inténtalo de nuevo.",
"save": "Guardar",
"security": "Contraseña",
"terms_and_tracking": "Jurídico y marketing",
Expand Down
17 changes: 17 additions & 0 deletions scripts/build-tools/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* eslint-disable no-console */
import fs from 'fs';

export const initSettings = (mode: string) => {
const localFile = `ini/.webapp.${mode}.ini`;
const templateFile = `ini/templates/.webapp.${mode}.ini`;

// The build ONLY uses .ini files in /ini to include in the build output.
// All .ini files in the directory are git ignored to customer specific values out of source control.
// However, this script will automatically create a .ini file for the current mode if it doesn't exist
// by copying the corresponding mode file from the ini/templates directory.
if (!fs.existsSync(localFile) && fs.existsSync(templateFile)) {
fs.copyFileSync(templateFile, localFile);
}

return localFile;
};
2 changes: 1 addition & 1 deletion scripts/content-types/content-types.json
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@
"description": "The playlist ID to display on this hub page",
"required": true,
"details": {
"field_type": "playlist_select"
"field_type": "playlist_multiselect"
}
},
{
Expand Down
4 changes: 2 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import React, { useEffect, useState } from 'react';
import { BrowserRouter } from 'react-router-dom';

import QueryProvider from '#src/containers/QueryProvider/QueryProvider';
import '#src/screenMapping';
import '#src/styles/main.scss';
import initI18n from '#src/i18n/config';
import Root from '#components/Root/Root';
import { ErrorPageWithoutTranslation } from '#components/ErrorPage/ErrorPage';
import LoadingOverlay from '#components/LoadingOverlay/LoadingOverlay';

import '#src/screenMapping';
import '#src/styles/main.scss';
interface State {
isLoading: boolean;
error?: Error;
Expand Down
13 changes: 13 additions & 0 deletions src/components/Account/Account.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ import customer from '#test/fixtures/customer.json';
import { useAccountStore } from '#src/stores/AccountStore';
import { renderWithRouter } from '#test/testUtils';
import type { Consent } from '#types/account';
import AccountController from '#src/stores/AccountController';

vi.mock('#src/modules/container', () => ({
getModule: (type: typeof AccountController) => {
switch (type) {
case AccountController:
return {
exportAccountData: vi.fn(),
getFeatures: vi.fn(() => ({ canChangePasswordWithOldPassword: false, canExportAccountData: false, canDeleteAccount: false })),
};
}
},
}));

describe('<Account>', () => {
test('renders and matches snapshot', () => {
Expand Down
Loading