Skip to content

Commit

Permalink
feat(project): services modularization (#363)
Browse files Browse the repository at this point in the history
feat(project)!: modularize services and controllers as classes

BREAKING CHANGES: this change is a big rewrite and will be more difficult to merge

---------

Co-authored-by: Christiaan Scheermeijer <christiaan@videodock.com>
  • Loading branch information
AntonLantukh and ChristiaanScheermeijer authored Nov 16, 2023
1 parent 18afd04 commit 6b1285b
Show file tree
Hide file tree
Showing 140 changed files with 5,118 additions and 3,994 deletions.
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
]
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"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
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;
};
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
25 changes: 13 additions & 12 deletions src/components/Account/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import useToggle from '#src/hooks/useToggle';
import { formatConsentsFromValues, formatConsents, formatConsentValues, formatConsentsToRegisterFields } from '#src/utils/collection';
import { addQueryParam } from '#src/utils/location';
import { useAccountStore } from '#src/stores/AccountStore';
import { exportAccountData, resetPassword, updateConsents, updateUser } from '#src/stores/AccountController';
import AccountController from '#src/stores/AccountController';
import { getModule } from '#src/modules/container';

type Props = {
panelClassName?: string;
Expand All @@ -41,11 +42,13 @@ interface FormErrors {
}

const Account = ({ panelClassName, panelHeaderClassName, canUpdateEmail = true }: Props): JSX.Element => {
const accountController = getModule(AccountController);

const { t } = useTranslation('user');
const navigate = useNavigate();
const location = useLocation();
const [viewPassword, toggleViewPassword] = useToggle();
const exportData = useMutation(exportAccountData);
const exportData = useMutation(accountController.exportAccountData);
const [isAlertVisible, setIsAlertVisible] = useState(false);
const exportDataMessage = exportData.isSuccess ? t('account.export_data_success') : t('account.export_data_error');

Expand All @@ -55,18 +58,16 @@ const Account = ({ panelClassName, panelHeaderClassName, canUpdateEmail = true }
}
}, [exportData.isSuccess, exportData.isError]);

const { customer, customerConsents, publisherConsents, canChangePasswordWithOldPassword, canExportAccountData, canDeleteAccount } = useAccountStore(
({ user, customerConsents, publisherConsents, canChangePasswordWithOldPassword, canExportAccountData, canDeleteAccount }) => ({
const { customer, customerConsents, publisherConsents } = useAccountStore(
({ user, customerConsents, publisherConsents }) => ({
customer: user,
customerConsents,
publisherConsents,
canChangePasswordWithOldPassword,
canExportAccountData,
canDeleteAccount,
}),
shallow,
);

const { canChangePasswordWithOldPassword, canExportAccountData, canDeleteAccount } = accountController.getFeatures();
// users authenticated with social (register_source: facebook, google, twitter) do not have password by default
const registerSource = customer?.metadata?.register_source;
const isSocialLogin = (registerSource && registerSource !== 'inplayer') || false;
Expand Down Expand Up @@ -183,7 +184,7 @@ const Account = ({ panelClassName, panelHeaderClassName, canUpdateEmail = true }
return;
}
if (isSocialLogin && shouldAddPassword) {
await resetPassword(customer.email, '');
await accountController.resetPassword(customer.email, '');
return navigate(addQueryParam(location, 'u', 'add-password'));
}
const modal = canChangePasswordWithOldPassword ? 'edit-password' : 'reset-password';
Expand All @@ -200,7 +201,7 @@ const Account = ({ panelClassName, panelHeaderClassName, canUpdateEmail = true }
onSubmit: (values) => {
const consents = formatConsentsFromValues(publisherConsents, { ...values.metadata, ...values.consentsValues });

return updateUser({
return accountController.updateUser({
firstName: values.firstName || '',
lastName: values.lastName || '',
metadata: {
Expand Down Expand Up @@ -238,7 +239,7 @@ const Account = ({ panelClassName, panelHeaderClassName, canUpdateEmail = true }
formSection({
label: t('account.email'),
onSubmit: (values) =>
updateUser({
accountController.updateUser({
email: values.email || '',
confirmationPassword: values.confirmationPassword,
}),
Expand Down Expand Up @@ -292,7 +293,7 @@ const Account = ({ panelClassName, panelHeaderClassName, canUpdateEmail = true }
formSection({
label: t('account.terms_and_tracking'),
saveButton: t('account.update_consents'),
onSubmit: (values) => updateConsents(formatConsentsFromValues(publisherConsents, values.consentsValues)),
onSubmit: (values) => accountController.updateConsents(formatConsentsFromValues(publisherConsents, values.consentsValues)),
content: (section) => (
<>
{termsConsents?.map((consent, index) => (
Expand All @@ -312,7 +313,7 @@ const Account = ({ panelClassName, panelHeaderClassName, canUpdateEmail = true }
formSection({
label: t('account.other_registration_details'),
saveButton: t('account.update_consents'),
onSubmit: (values) => updateConsents(formatConsentsFromValues(publisherConsents, values.consentsValues)),
onSubmit: (values) => accountController.updateConsents(formatConsentsFromValues(publisherConsents, values.consentsValues)),
content: (section) => (
<div className={styles.customFields} data-testid={testId('custom-reg-fields')}>
{nonTermsConsents.map((consent) => (
Expand Down
9 changes: 6 additions & 3 deletions src/components/DeleteAccountModal/DeleteAccountModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,20 @@ import styles from './DeleteAccountModal.module.scss';
import type { DeleteAccountFormData } from '#types/account';
import useForm from '#src/hooks/useForm';
import { addQueryParam, removeQueryParam } from '#src/utils/location';
import { deleteAccountData, logout } from '#src/stores/AccountController';
import Alert from '#components/Alert/Alert';
import AccountController from '#src/stores/AccountController';
import { getModule } from '#src/modules/container';

const DeleteAccountModal = () => {
const accountController = getModule(AccountController);

const { t } = useTranslation('user');

const [enteredPassword, setEnteredPassword] = useState<string>('');

const deleteAccount = useMutation(deleteAccountData, {
const deleteAccount = useMutation(accountController.deleteAccountData, {
onSuccess: async () => {
await logout();
await accountController.logout();
navigate('/');
},
onError: () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ import styles from './DeleteAccountPasswordWarning.module.scss';

import { addQueryParam, removeQueryParam } from '#src/utils/location';
import { useAccountStore } from '#src/stores/AccountStore';
import { resetPassword } from '#src/stores/AccountController';
import AccountController from '#src/stores/AccountController';
import FormFeedback from '#components/FormFeedback/FormFeedback';
import { getModule } from '#src/modules/container';

const DeleteAccountPasswordWarning = () => {
const accountController = getModule(AccountController);

const { t } = useTranslation('user');
const email = useAccountStore((state) => state.user?.email);
const [errorMessage, setErrorMessage] = useState<string>();
Expand All @@ -24,7 +27,7 @@ const DeleteAccountPasswordWarning = () => {
const proceedToAddPasswordClickHandler = async () => {
try {
if (email) {
await resetPassword(email, '');
await accountController.resetPassword(email, '');
navigate(addQueryParam(location, 'u', 'add-password'));
}
} catch (error: unknown) {
Expand Down
24 changes: 20 additions & 4 deletions src/components/DemoConfigDialog/DemoConfigDialog.test.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
import React from 'react';
import type { UseQueryResult } from 'react-query';

import { renderWithRouter } from '#test/testUtils';
import DemoConfigDialog from '#components/DemoConfigDialog/DemoConfigDialog';
import type { Config } from '#types/Config';

describe('<DemoConfigDialog>', () => {
test('renders and matches snapshot', () => {
const { container } = renderWithRouter(<DemoConfigDialog configQuery={{ isSuccess: true } as UseQueryResult<Config>} selectedConfigSource={'abcdefgh'} />);
const query = {
isSuccess: true,
error: null,
isLoading: false,
data: { configSource: 'abcdefgh', config: {}, settings: {} },
refetch: () => Promise.resolve(null),
};

// @ts-expect-error
const { container } = renderWithRouter(<DemoConfigDialog query={query} />);

expect(container).toMatchSnapshot();
});

test('renders and matches snapshot error dialog', () => {
const { container } = renderWithRouter(<DemoConfigDialog configQuery={{ isSuccess: false } as UseQueryResult<Config>} selectedConfigSource={'aaaaaaaa'} />);
const query = {
isSuccess: false,
error: new Error('smth'),
isLoading: false,
data: { configSource: 'aaaaaaaa', config: {}, settings: {} },
refetch: () => Promise.resolve(null),
};

// @ts-expect-error
const { container } = renderWithRouter(<DemoConfigDialog query={query} />);

expect(container).toMatchSnapshot();
});
Expand Down
Loading

0 comments on commit 6b1285b

Please sign in to comment.