Skip to content

Commit 301d829

Browse files
committed
Merge branch 'release-candidate' into release
2 parents 635abf6 + 1ff6fdd commit 301d829

File tree

166 files changed

+3417
-2854
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

166 files changed

+3417
-2854
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
## [6.1.2](https://github.com/jwplayer/ott-web-app/compare/v6.1.1...v6.1.2) (2024-05-21)
2+
3+
4+
### Bug Fixes
5+
6+
* **a11y:** improve accessibility of offers modal ([af654ec](https://github.com/jwplayer/ott-web-app/commit/af654ecc9b481353522b8e08a2d8078a7b91aa2a))
7+
* **home:** broken home skeleton ([#523](https://github.com/jwplayer/ott-web-app/issues/523)) ([35cd2db](https://github.com/jwplayer/ott-web-app/commit/35cd2db26ed3ffee65a6e2edf38447bce7957c7f))
8+
* **menu:** reintroduce profile menu styling ([39fd840](https://github.com/jwplayer/ott-web-app/commit/39fd840019405797069e84f7dbfd9d10a746b534))
9+
* **project:** alignment of password toggle button ([642068d](https://github.com/jwplayer/ott-web-app/commit/642068dc4babba8e9660e9bfee6acf16931aa8aa))
10+
* **project:** favicon paths ([7acf234](https://github.com/jwplayer/ott-web-app/commit/7acf234446d8dc62e3f43b13f49c3b2ad3c72a8a))
11+
* remove simultaneous logins ([9aa4a71](https://github.com/jwplayer/ott-web-app/commit/9aa4a71d8c12865bdf13fadf3d93b420343bd672))
12+
113
## [6.1.1](https://github.com/jwplayer/ott-web-app/compare/v6.1.0...v6.1.1) (2024-04-23)
214

315

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@jwp/ott",
3-
"version": "6.1.1",
3+
"version": "6.1.2",
44
"private": true,
55
"license": "Apache-2.0",
66
"repository": "https://github.com/jwplayer/ott-web-app.git",

packages/common/src/constants.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@ export const DEFAULT_FEATURES = {
7575
watchListSizeLimit: MAX_WATCHLIST_ITEMS_COUNT,
7676
};
7777

78-
export const simultaneousLoginWarningKey = 'simultaneous_logins';
79-
8078
export const EPG_TYPE = {
8179
jwp: 'jwp',
8280
viewNexa: 'viewnexa',

packages/common/src/controllers/AccountController.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ export default class AccountController {
334334

335335
if (response.errors.length > 0) throw new Error(response.errors[0]);
336336

337-
await this.reloadSubscriptions({ delay: 2000 });
337+
await this.reloadSubscriptions({ retry: 10 });
338338

339339
return response?.responseData;
340340
};
@@ -386,7 +386,7 @@ export default class AccountController {
386386
return !!responseData?.accessGranted;
387387
};
388388

389-
reloadSubscriptions = async ({ delay }: { delay: number } = { delay: 0 }): Promise<unknown> => {
389+
reloadSubscriptions = async ({ delay, retry }: { delay?: number; retry?: number } = { delay: 0, retry: 0 }): Promise<unknown> => {
390390
useAccountStore.setState({ loading: true });
391391

392392
const { getAccountInfo } = useAccountStore.getState();
@@ -395,10 +395,10 @@ export default class AccountController {
395395

396396
// The subscription data takes a few seconds to load after it's purchased,
397397
// so here's a delay mechanism to give it time to process
398-
if (delay > 0) {
398+
if (delay && delay > 0) {
399399
return new Promise((resolve: (value?: unknown) => void) => {
400400
setTimeout(() => {
401-
this.reloadSubscriptions().finally(resolve);
401+
this.reloadSubscriptions({ retry }).finally(resolve);
402402
}, delay);
403403
});
404404
}
@@ -418,6 +418,12 @@ export default class AccountController {
418418

419419
let pendingOffer: Offer | null = null;
420420

421+
if (!activeSubscription && !!retry && retry > 0) {
422+
const retryDelay = 1500; // Any initial delay has already occured, so we can set this to a fixed value
423+
424+
return await this.reloadSubscriptions({ delay: retryDelay, retry: retry - 1 });
425+
}
426+
421427
// resolve and fetch the pending offer after upgrade/downgrade
422428
try {
423429
if (activeSubscription?.pendingSwitchId) {

packages/common/src/stores/UIStore.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ type UIState = {
44
searchQuery: string;
55
searchActive: boolean;
66
userMenuOpen: boolean;
7+
sideBarOpen: boolean;
78
languageMenuOpen: boolean;
89
preSearchPage?: string;
910
};
@@ -12,5 +13,6 @@ export const useUIStore = createStore<UIState>('UIStore', () => ({
1213
searchQuery: '',
1314
searchActive: false,
1415
userMenuOpen: false,
16+
sideBarOpen: false,
1517
languageMenuOpen: false,
1618
}));

packages/common/types/form.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
export type UseFormChangeHandler = React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>;
2-
export type UseFormBlurHandler = React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
1+
export type UseFormChangeHandler = React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>;
2+
export type UseFormBlurHandler = React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>;
33
export type UseFormSubmitHandler = React.FormEventHandler<HTMLFormElement>;
44

55
export type GenericFormErrors = { form: string };

packages/hooks-react/src/useCheckAccess.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const useCheckAccess = () => {
3131
const hasAccess = await accountController.checkEntitlements(offerId);
3232

3333
if (hasAccess) {
34-
await accountController.reloadSubscriptions({ delay: 2000 }); // Delay needed for backend processing (Cleeng API returns empty subscription, even after accessGranted from entitlements call
34+
await accountController.reloadSubscriptions({ retry: 10, delay: 2000 });
3535
callback?.(true);
3636
} else if (--iterations === 0) {
3737
window.clearInterval(intervalRef.current);

packages/hooks-react/src/useCheckout.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const useCheckout = ({ onUpdateOrderSuccess, onSubmitPaymentWithoutDetailsSucces
4747
mutationKey: ['submitPaymentWithoutDetails'],
4848
mutationFn: checkoutController.paymentWithoutDetails,
4949
onSuccess: async () => {
50-
await accountController.reloadSubscriptions({ delay: 1000 });
50+
await accountController.reloadSubscriptions({ retry: 10 });
5151
onSubmitPaymentWithoutDetailsSuccess();
5252
},
5353
});

packages/hooks-react/src/useOffers.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { useMutation } from 'react-query';
2-
import { useEffect } from 'react';
1+
import { useMutation, useQuery } from 'react-query';
32
import { shallow } from '@jwp/ott-common/src/utils/compare';
43
import { getModule } from '@jwp/ott-common/src/modules/container';
54
import { useCheckoutStore } from '@jwp/ott-common/src/stores/CheckoutStore';
@@ -21,9 +20,9 @@ const useOffers = () => {
2120
shallow,
2221
);
2322

24-
const { mutate: initialise, isLoading: isInitialisationLoading } = useMutation<void>({
25-
mutationKey: ['initialiseOffers', requestedMediaOffers],
26-
mutationFn: checkoutController.initialiseOffers,
23+
const { isLoading: isInitialisationLoading } = useQuery<void>({
24+
queryKey: ['initialiseOffers', requestedMediaOffers],
25+
queryFn: checkoutController.initialiseOffers,
2726
});
2827

2928
const chooseOffer = useMutation({
@@ -34,13 +33,9 @@ const useOffers = () => {
3433
const switchSubscription = useMutation({
3534
mutationKey: ['switchSubscription'],
3635
mutationFn: checkoutController.switchSubscription,
37-
onSuccess: () => accountController.reloadSubscriptions({ delay: 7500 }), // @todo: Is there a better way to wait?
36+
onSuccess: () => accountController.reloadSubscriptions({ delay: 3000, retry: 10 }), // A subscription switch usually takes at least 3 secs
3837
});
3938

40-
useEffect(() => {
41-
initialise();
42-
}, [requestedMediaOffers, initialise]);
43-
4439
const hasMediaOffers = mediaOffers.length > 0;
4540
const hasSubscriptionOffers = subscriptionOffers.length > 0;
4641
const hasPremierOffers = requestedMediaOffers.some((mediaOffer) => mediaOffer.premier);

packages/hooks-react/src/usePlaylists.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ const placeholderData = generatePlaylistPlaceholder(30);
1414

1515
type UsePlaylistResult = {
1616
data: Playlist | undefined;
17-
isLoading: boolean;
1817
isSuccess?: boolean;
1918
error?: unknown;
19+
isPlaceholderData?: boolean;
2020
}[];
2121

2222
const usePlaylists = (content: Content[], rowsToLoad: number | undefined = undefined) => {
@@ -57,13 +57,13 @@ const usePlaylists = (content: Content[], rowsToLoad: number | undefined = undef
5757
if (type === PersonalShelf.Favorites) return { data: favorites, isLoading: false, isSuccess: true };
5858
if (type === PersonalShelf.ContinueWatching) return { data: watchHistory, isLoading: false, isSuccess: true };
5959

60-
const { data, isLoading, isSuccess, error } = playlistQueries[index];
60+
const { data, isSuccess, error, isPlaceholderData } = playlistQueries[index];
6161

6262
return {
6363
data,
64-
isLoading,
6564
isSuccess,
6665
error,
66+
isPlaceholderData,
6767
};
6868
});
6969

packages/hooks-react/src/useProfiles.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { useAccountStore } from '@jwp/ott-common/src/stores/AccountStore';
1010
import ProfileController from '@jwp/ott-common/src/controllers/ProfileController';
1111
import AccountController from '@jwp/ott-common/src/controllers/AccountController';
1212
import { logDev } from '@jwp/ott-common/src/utils/common';
13+
import { useConfigStore } from '@jwp/ott-common/src/stores/ConfigStore';
1314

1415
export const useSelectProfile = (options?: { onSuccess: () => void; onError: () => void }) => {
1516
const accountController = getModule(AccountController, false);
@@ -94,7 +95,9 @@ export const useProfileErrorHandler = () => {
9495
};
9596

9697
export const useProfiles = (options?: UseQueryOptions<ListProfilesResponse | undefined, unknown, ListProfilesResponse | undefined, string[]>) => {
97-
const { user } = useAccountStore();
98+
const user = useAccountStore((state) => state.user);
99+
const accessModel = useConfigStore((state) => state.accessModel);
100+
const { profile } = useProfileStore();
98101
const isLoggedIn = !!user;
99102

100103
const profileController = getModule(ProfileController);
@@ -106,8 +109,11 @@ export const useProfiles = (options?: UseQueryOptions<ListProfilesResponse | und
106109
enabled: isLoggedIn && profilesEnabled,
107110
});
108111

112+
const shouldManageProfiles = !!user && profilesEnabled && query.data?.canManageProfiles && !profile && (accessModel === 'SVOD' || accessModel === 'AUTHVOD');
113+
109114
return {
110115
query,
116+
shouldManageProfiles,
111117
profilesEnabled: !!query.data?.canManageProfiles,
112118
};
113119
};

packages/ui-react/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
"typescript-plugin-css-modules": "^5.0.2",
4646
"vi-fetch": "^0.8.0",
4747
"vite-plugin-svgr": "^4.2.0",
48-
"vitest": "^1.3.1"
48+
"vitest": "^1.3.1",
49+
"wicg-inert": "^3.1.2"
4950
},
5051
"peerDependencies": {
5152
"@jwp/ott-common": "*",

packages/ui-react/src/components/Account/Account.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ import Alert from '../Alert/Alert';
2020
import Button from '../Button/Button';
2121
import Form from '../Form/Form';
2222
import IconButton from '../IconButton/IconButton';
23-
import TextField from '../TextField/TextField';
24-
import Checkbox from '../Checkbox/Checkbox';
2523
import FormFeedback from '../FormFeedback/FormFeedback';
24+
import TextField from '../form-fields/TextField/TextField';
25+
import Checkbox from '../form-fields/Checkbox/Checkbox';
2626
import CustomRegisterField from '../CustomRegisterField/CustomRegisterField';
2727
import Icon from '../Icon/Icon';
2828
import { modalURLFromLocation } from '../../utils/location';
@@ -351,8 +351,9 @@ const Account = ({ panelClassName, panelHeaderClassName, canUpdateEmail = true }
351351
name={`consentsValues.${consent.name}`}
352352
checked={isTruthyCustomParamValue(section.values.consentsValues?.[consent.name])}
353353
onChange={section.onChange}
354-
label={formatConsentLabel(consent.label)}
354+
checkboxLabel={formatConsentLabel(consent.label)}
355355
disabled={consent.required || section.isBusy}
356+
required={consent.required}
356357
lang={htmlLang}
357358
/>
358359
))}

packages/ui-react/src/components/Account/__snapshots__/Account.test.tsx.snap

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,20 @@ exports[`<Account> > renders and matches snapshot 1`] = `
2525
novalidate=""
2626
>
2727
<div
28-
class="_textField_e16c1b"
28+
class="_formField_86f2f5 _textField_c799b0"
2929
>
3030
<label
31-
class="_label_e16c1b"
31+
class="_label_86f2f5"
3232
for="text-field_1235_firstname"
3333
>
3434
account.firstname
3535
</label>
3636
<input
3737
aria-describedby="helper_text_1235_firstname"
3838
aria-invalid="false"
39+
aria-required="false"
3940
autocomplete="given-name"
40-
class="_input_e16c1b"
41+
class="_input_859b20"
4142
id="text-field_1235_firstname"
4243
lang="en"
4344
name="firstName"
@@ -47,19 +48,20 @@ exports[`<Account> > renders and matches snapshot 1`] = `
4748
/>
4849
</div>
4950
<div
50-
class="_textField_e16c1b"
51+
class="_formField_86f2f5 _textField_c799b0"
5152
>
5253
<label
53-
class="_label_e16c1b"
54+
class="_label_86f2f5"
5455
for="text-field_1235_lastname"
5556
>
5657
account.lastname
5758
</label>
5859
<input
5960
aria-describedby="helper_text_1235_lastname"
6061
aria-invalid="false"
62+
aria-required="false"
6163
autocomplete="family-name"
62-
class="_input_e16c1b"
64+
class="_input_859b20"
6365
id="text-field_1235_lastname"
6466
lang="en"
6567
name="lastName"
@@ -100,19 +102,20 @@ exports[`<Account> > renders and matches snapshot 1`] = `
100102
novalidate=""
101103
>
102104
<div
103-
class="_textField_e16c1b"
105+
class="_formField_86f2f5 _textField_c799b0"
104106
>
105107
<label
106-
class="_label_e16c1b"
108+
class="_label_86f2f5"
107109
for="text-field_1235_email"
108110
>
109111
account.email
110112
</label>
111113
<input
112114
aria-describedby="helper_text_1235_email"
113115
aria-invalid="false"
116+
aria-required="true"
114117
autocomplete="email"
115-
class="_input_e16c1b"
118+
class="_input_859b20"
116119
id="text-field_1235_email"
117120
name="email"
118121
readonly=""
@@ -183,25 +186,22 @@ exports[`<Account> > renders and matches snapshot 1`] = `
183186
novalidate=""
184187
>
185188
<div
186-
class="_checkbox_531f07"
189+
class="_formField_86f2f5 _checkbox_a98c3a"
187190
>
188191
<div
189-
class="_row_531f07"
192+
class="_row_a98c3a"
190193
>
191194
<input
192195
aria-describedby="helper_text_1235_consentsvalues_marketing"
193-
id="check-box_1235_consentsvalues_marketing"
196+
id="text-field_1235_consentsvalues_marketing"
194197
name="consentsValues.marketing"
195198
type="checkbox"
196199
value=""
197200
/>
198201
<label
199-
for="check-box_1235_consentsvalues_marketing"
202+
for="text-field_1235_consentsvalues_marketing"
200203
lang="en"
201204
>
202-
<span
203-
aria-hidden="true"
204-
/>
205205
Receive Marketing Emails
206206
</label>
207207
</div>
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import React from 'react';
2-
import { render } from '@testing-library/react';
2+
3+
import { renderWithRouter } from '../../../test/utils';
34

45
import Alert from './Alert';
56

67
describe('<Alert>', () => {
78
test('renders and matches snapshot', () => {
8-
const { container } = render(<Alert message="Body" open={true} onClose={vi.fn()} />);
9+
const { container } = renderWithRouter(<Alert message="Body" open={true} onClose={vi.fn()} />);
910
expect(container).toMatchSnapshot();
1011
});
1112
});

0 commit comments

Comments
 (0)