Skip to content

Commit

Permalink
fix: add various profiles fixes and improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
naumovski-filip committed Sep 11, 2023
1 parent 71343d6 commit 4d85c1c
Show file tree
Hide file tree
Showing 13 changed files with 109 additions and 103 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"lint:stylelint": "stylelint '**/*.{css,scss}'",
"commit-msg": "commitlint --edit $1",
"codecept:mobile": "cd test-e2e && rm -rf \"./output/mobile\" && codeceptjs --config ./codecept.mobile.js run-workers --suites ${WORKER_COUNT:=8} ",
"codecept:desktop": "cd test-e2e && rm -rf \"./output/desktop\" && codeceptjs --config ./codecept.desktop.js run-workers --suites ${WORKER_COUNT:=2} ",
"codecept:desktop": "cd test-e2e && rm -rf \"./output/desktop\" && codeceptjs --config ./codecept.desktop.js run-workers --suites ${WORKER_COUNT:=8} ",
"serve-report:mobile": "cd test-e2e && allure serve \"./output/mobile\"",
"serve-report:desktop": "cd test-e2e && allure serve \"./output/desktop\"",
"codecept-serve:mobile": "yarn codecept:mobile ; yarn serve-report:mobile",
Expand Down
4 changes: 1 addition & 3 deletions src/components/Root/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { initSettings } from '#src/stores/SettingsController';
import AppRoutes from '#src/containers/AppRoutes/AppRoutes';
import registerCustomScreens from '#src/screenMapping';
import { useAccountStore } from '#src/stores/AccountStore';
import { useProfilesFeatureEnabled } from '#src/hooks/useProfiles';
import { useProfileStore } from '#src/stores/ProfileStore';

const Root: FC = () => {
Expand Down Expand Up @@ -51,9 +50,8 @@ const Root: FC = () => {
const userData = useAccountStore((s) => ({ loading: s.loading, user: s.user }));

const { profile, selectingProfileAvatar } = useProfileStore();
const profilesEnabled = useProfilesFeatureEnabled();

if (userData.user && profilesEnabled && selectingProfileAvatar !== null) {
if (userData.user && selectingProfileAvatar !== null) {
return <LoadingOverlay profileImageUrl={selectingProfileAvatar || profile?.avatar_url} />;
}

Expand Down
65 changes: 65 additions & 0 deletions src/components/UserMenu/ProfilesMenu/ProfilesMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import classNames from 'classnames';
import type { UseMutateFunction } from 'react-query';

import styles from '../UserMenu.module.scss';

import LoadingOverlay from '#components/LoadingOverlay/LoadingOverlay';
import MenuButton from '#components/MenuButton/MenuButton';
import Plus from '#src/icons/Plus';
import ProfileCircle from '#src/icons/ProfileCircle';
import type { Profile } from '#types/account';

type ProfilesMenuProps = {
profiles: Profile[];
currentProfile?: Profile;
small?: boolean;
selectingProfile: boolean;
selectProfile: UseMutateFunction<unknown, unknown, { id: string; avatarUrl: string }, unknown>;
defaultAvatar: string;
createButtonLabel?: string;
switchProfilesLabel?: string;
onCreateButtonClick: () => void;
};

const ProfilesMenu = ({
profiles,
currentProfile,
small,
selectingProfile,
selectProfile,
defaultAvatar,
createButtonLabel,
switchProfilesLabel,
onCreateButtonClick,
}: ProfilesMenuProps) => (
<>
<li className={styles.sectionHeader}>{switchProfilesLabel}</li>
{selectingProfile ? (
<LoadingOverlay inline />
) : (
profiles?.map((profile) => (
<li key={profile.id}>
<MenuButton
active={profile.id === currentProfile?.id}
small={small}
onClick={() => selectProfile({ id: profile.id, avatarUrl: profile.avatar_url })}
label={profile.name}
startIcon={<ProfileCircle src={profile.avatar_url || defaultAvatar} alt={profile.name} />}
/>
</li>
))
)}
{(profiles?.length || 0) < 4 && (
<li>
<MenuButton small={small} onClick={onCreateButtonClick} startIcon={<Plus />} label={createButtonLabel} />
</li>
)}
<hr
className={classNames(styles.divider, {
[styles.small]: small,
})}
/>
</>
);

export default ProfilesMenu;
42 changes: 12 additions & 30 deletions src/components/UserMenu/UserMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ import { useTranslation } from 'react-i18next';
import classNames from 'classnames';

import styles from './UserMenu.module.scss';
import ProfilesMenu from './ProfilesMenu/ProfilesMenu';

import AccountCircle from '#src/icons/AccountCircle';
import Favorite from '#src/icons/Favorite';
import BalanceWallet from '#src/icons/BalanceWallet';
import Exit from '#src/icons/Exit';
import MenuButton from '#components/MenuButton/MenuButton';
import { logout } from '#src/stores/AccountController';
import LoadingOverlay from '#components/LoadingOverlay/LoadingOverlay';
import Plus from '#src/icons/Plus';
import { useSelectProfile } from '#src/hooks/useProfiles';
import ProfileCircle from '#src/icons/ProfileCircle';
import type { AccessModel } from '#types/Config';
Expand Down Expand Up @@ -47,34 +46,17 @@ const UserMenu = ({ showPaymentsItem, small = false, onClick, accessModel, curre
return (
<ul className={styles.menuItems}>
{accessModel === 'SVOD' && profilesEnabled && (
<>
<li className={styles.sectionHeader}>{t('nav.switch_profiles')}</li>
{selectProfile.isLoading ? (
<LoadingOverlay inline />
) : (
profiles?.map((profile) => (
<li key={profile.id}>
<MenuButton
active={profile.id === currentProfile?.id}
small={small}
onClick={() => selectProfile.mutate({ id: profile.id, avatarUrl: profile.avatar_url })}
label={profile.name}
startIcon={<ProfileCircle src={profile.avatar_url || defaultAvatar} alt={profile.name} />}
/>
</li>
))
)}
{(profiles?.length || 0) < 4 && (
<li>
<MenuButton small={small} onClick={() => navigate('/u/profiles/create')} label={t('nav.add_profile')} startIcon={<Plus />} />
</li>
)}
<hr
className={classNames(styles.divider, {
[styles.small]: small,
})}
/>
</>
<ProfilesMenu
profiles={profiles ?? []}
currentProfile={currentProfile}
small={small}
selectingProfile={selectProfile.isLoading}
selectProfile={selectProfile.mutate}
defaultAvatar={defaultAvatar}
createButtonLabel={t('nav.add_profile')}
switchProfilesLabel={t('nav.switch_profiles')}
onCreateButtonClick={() => navigate('/u/profiles/create')}
/>
)}
<li className={styles.sectionHeader}>{t('nav.settings')}</li>
{profilesEnabled && currentProfile && (
Expand Down
4 changes: 4 additions & 0 deletions src/containers/AccountModal/forms/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { object, SchemaOf, string } from 'yup';
import { useTranslation } from 'react-i18next';
import { useLocation, useNavigate } from 'react-router';
import { useQueryClient } from 'react-query';

import { useConfigStore } from '#src/stores/ConfigStore';
import useForm, { UseFormOnSubmitHandler } from '#src/hooks/useForm';
Expand All @@ -20,9 +21,12 @@ const Login: React.FC<Props> = ({ messageKey }: Props) => {
const location = useLocation();
const { t } = useTranslation('account');

const queryClient = useQueryClient();

const loginSubmitHandler: UseFormOnSubmitHandler<LoginFormData> = async (formData, { setErrors, setSubmitting, setValue }) => {
try {
await login(formData.email, formData.password);
await queryClient.invalidateQueries('listProfiles');

// close modal
navigate(removeQueryParam(location, 'u'));
Expand Down
4 changes: 2 additions & 2 deletions src/containers/AppRoutes/AppRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import { useConfigStore } from '#src/stores/ConfigStore';
import { useAccountStore } from '#src/stores/AccountStore';
import EditProfile from '#src/containers/Profiles/EditProfile';
import useQueryParam from '#src/hooks/useQueryParam';
import { useProfilesFeatureEnabled } from '#src/hooks/useProfiles';
import { useProfileStore } from '#src/stores/ProfileStore';
import { useProfiles } from '#src/hooks/useProfiles';

export default function AppRoutes() {
const location = useLocation();
Expand All @@ -31,7 +31,7 @@ export default function AppRoutes() {
const { accessModel } = useConfigStore(({ config, accessModel }) => ({ config, accessModel }), shallow);
const user = useAccountStore(({ user }) => user, shallow);
const { profile } = useProfileStore();
const profilesEnabled = useProfilesFeatureEnabled();
const { profilesEnabled } = useProfiles();

const shouldManageProfiles =
!!user && profilesEnabled && !profile && (accessModel === 'SVOD' || accessModel === 'AUTHVOD') && !userModal && !location.pathname.includes('/u/profiles');
Expand Down
10 changes: 4 additions & 6 deletions src/containers/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,13 @@ import UserMenu from '#components/UserMenu/UserMenu';
import { addQueryParam } from '#src/utils/location';
import { getSupportedLanguages } from '#src/i18n/config';
import { useProfileStore } from '#src/stores/ProfileStore';
import { unpersistProfile, useListProfiles, useProfilesFeatureEnabled } from '#src/hooks/useProfiles';
import { unpersistProfile, useProfiles } from '#src/hooks/useProfiles';

const Layout = () => {
const location = useLocation();
const navigate = useNavigate();
const { t, i18n } = useTranslation('common');
const { config, accessModel } = useConfigStore(({ config, accessModel }) => ({ config, accessModel }), shallow);
const { data: profilesData } = useListProfiles();
const profiles = profilesData?.responseData.collection;
const profilesEnabled = useProfilesFeatureEnabled();
const { menu, assets, siteName, description, styling, features } = config;
const metaDescription = description || t('default_description');
const { clientId } = useClientIntegration();
Expand All @@ -38,6 +35,8 @@ const Layout = () => {
const supportedLanguages = useMemo(() => getSupportedLanguages(), []);
const currentLanguage = useMemo(() => supportedLanguages.find(({ code }) => code === i18n.language), [i18n.language, supportedLanguages]);

const { data: { responseData: { collection: profiles = [] } = {} } = {}, profilesEnabled } = useProfiles();

if (profilesEnabled && !profiles?.length) {
unpersistProfile();
}
Expand All @@ -52,9 +51,8 @@ const Layout = () => {
shallow,
);
const { updateSearchQuery, resetSearchQuery } = useSearchQueryUpdater();
const user = useAccountStore(({ user }) => user);
const { profile } = useProfileStore();
const isLoggedIn = !!user;
const isLoggedIn = !!useAccountStore(({ user }) => user);

const searchInputRef = useRef<HTMLInputElement>(null) as React.MutableRefObject<HTMLInputElement>;

Expand Down
8 changes: 4 additions & 4 deletions src/containers/Profiles/CreateProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import type { ProfileFormValues } from './types';
import LoadingOverlay from '#src/components/LoadingOverlay/LoadingOverlay';
import useBreakpoint, { Breakpoint } from '#src/hooks/useBreakpoint';
import type { UseFormOnSubmitHandler } from '#src/hooks/useForm';
import { useCreateProfile, useListProfiles, useProfilesFeatureEnabled } from '#src/hooks/useProfiles';
import { useCreateProfile, useProfiles } from '#src/hooks/useProfiles';
import styles from '#src/pages/User/User.module.scss';

const CreateProfile = () => {
const navigate = useNavigate();
const profilesEnabled = useProfilesFeatureEnabled();
const { profilesEnabled } = useProfiles();

const [avatarUrl, setAvatarUrl] = useState<string>(AVATARS[Math.floor(Math.random() * AVATARS.length)]);

Expand All @@ -27,7 +27,7 @@ const CreateProfile = () => {
if (!profilesEnabled) navigate('/');
}, [profilesEnabled, navigate]);

const listProfiles = useListProfiles();
const { isLoading: loadingProfilesList } = useProfiles();

const initialValues = {
name: '',
Expand Down Expand Up @@ -55,7 +55,7 @@ const CreateProfile = () => {
},
);

if (listProfiles.isLoading) return <LoadingOverlay inline />;
if (loadingProfilesList) return <LoadingOverlay inline />;

return (
<div className={styles.user}>
Expand Down
8 changes: 2 additions & 6 deletions src/containers/Profiles/Profiles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { Profile } from '#types/account';
import AddNewProfile from '#src/components/ProfileBox/AddNewProfile';
import LoadingOverlay from '#src/components/LoadingOverlay/LoadingOverlay';
import Button from '#src/components/Button/Button';
import { useSelectProfile, useListProfiles, useProfilesFeatureEnabled } from '#src/hooks/useProfiles';
import { useSelectProfile, useProfiles } from '#src/hooks/useProfiles';
import useBreakpoint, { Breakpoint } from '#src/hooks/useBreakpoint';
const MAX_PROFILES = 4;

Expand All @@ -23,15 +23,11 @@ const Profiles = ({ editMode = false }: Props) => {
const navigate = useNavigate();
const { t } = useTranslation('user');
const { loading, user } = useAccountStore(({ loading, user }) => ({ loading, user }), shallow);
const profilesEnabled = useProfilesFeatureEnabled();

const breakpoint: Breakpoint = useBreakpoint();
const isMobile = breakpoint === Breakpoint.xs;

const { data, isLoading, isFetching, isError } = useListProfiles({
refetchOnMount: true,
staleTime: 0,
});
const { data, isLoading, isFetching, isError, profilesEnabled } = useProfiles();

const activeProfiles = data?.responseData.collection.length || 0;
const canAddNew = activeProfiles < MAX_PROFILES;
Expand Down
22 changes: 12 additions & 10 deletions src/hooks/useProfiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { UseMutationOptions, UseQueryOptions, useMutation, useQuery } from 'reac
import { useNavigate } from 'react-router';

import { initializeAccount } from '#src/stores/AccountController';
import { useAccountStore } from '#src/stores/AccountStore';
import { useFavoritesStore } from '#src/stores/FavoritesStore';
import { createProfile, deleteProfile, enterProfile, listProfiles, updateProfile } from '#src/stores/ProfileController';
import { useProfileStore } from '#src/stores/ProfileStore';
import { useWatchHistoryStore } from '#src/stores/WatchHistoryStore';
import * as persist from '#src/utils/persist';
import type { AuthData, CommonAccountResponse, ListProfilesResponse, ProfileDetailsPayload, ProfilePayload } from '#types/account';
import { useAccountStore } from '#src/stores/AccountStore';

const PERSIST_KEY_ACCOUNT = 'auth';
const PERSIST_PROFILE = 'profile';
Expand Down Expand Up @@ -57,7 +57,7 @@ export const useSelectProfile = () => {
};

export const useCreateProfile = (options?: UseMutationOptions<ServiceResponse<ProfilesData> | undefined, unknown, ProfilePayload, unknown>) => {
const listProfiles = useListProfiles();
const listProfiles = useProfiles();
const navigate = useNavigate();

return useMutation<ServiceResponse<ProfilesData> | undefined, unknown, ProfilePayload, unknown>(createProfile, {
Expand All @@ -73,7 +73,7 @@ export const useCreateProfile = (options?: UseMutationOptions<ServiceResponse<Pr
};

export const useUpdateProfile = (options?: UseMutationOptions<ServiceResponse<ProfilesData> | undefined, unknown, ProfilePayload, unknown>) => {
const listProfiles = useListProfiles();
const listProfiles = useProfiles();
const navigate = useNavigate();

return useMutation(updateProfile, {
Expand All @@ -91,7 +91,7 @@ export const useUpdateProfile = (options?: UseMutationOptions<ServiceResponse<Pr
};

export const useDeleteProfile = (options?: UseMutationOptions<ServiceResponse<CommonAccountResponse> | undefined, unknown, ProfileDetailsPayload, unknown>) => {
const listProfiles = useListProfiles();
const listProfiles = useProfiles();
const navigate = useNavigate();

return useMutation<ServiceResponse<CommonAccountResponse> | undefined, unknown, ProfileDetailsPayload, unknown>(deleteProfile, {
Expand All @@ -103,11 +103,13 @@ export const useDeleteProfile = (options?: UseMutationOptions<ServiceResponse<Co
});
};

export const useListProfiles = (
export const useProfiles = (
options?: UseQueryOptions<ServiceResponse<ListProfilesResponse> | undefined, unknown, ServiceResponse<ListProfilesResponse> | undefined, string[]>,
) => useQuery(['listProfiles'], listProfiles, { ...options });

export const useProfilesFeatureEnabled = (): boolean => {
const canManageProfiles = useAccountStore((s) => s.canManageProfiles);
return canManageProfiles;
) => {
const query = useQuery(['listProfiles'], listProfiles, { ...options });
const { canManageProfiles } = useAccountStore();
if (!canManageProfiles && query.data?.responseData.canManageProfiles) {
useAccountStore.setState({ canManageProfiles: true });
}
return { ...query, profilesEnabled: query.data?.responseData.canManageProfiles && canManageProfiles };
};
4 changes: 2 additions & 2 deletions src/pages/User/User.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ import { logout } from '#src/stores/AccountController';
import { useAccountStore } from '#src/stores/AccountStore';
import { getSubscriptionSwitches } from '#src/stores/CheckoutController';
import EditProfile from '#src/containers/Profiles/EditProfile';
import { useProfilesFeatureEnabled } from '#src/hooks/useProfiles';
import { PersonalShelf, useConfigStore } from '#src/stores/ConfigStore';
import { clear as clearFavorites } from '#src/stores/FavoritesController';
import { useProfileStore } from '#src/stores/ProfileStore';
import { useProfiles } from '#src/hooks/useProfiles';

const User = (): JSX.Element => {
const { accessModel, favoritesList } = useConfigStore(
Expand All @@ -44,7 +44,7 @@ const User = (): JSX.Element => {
const { user: customer, subscription, loading, canUpdateEmail } = useAccountStore();
const { profile } = useProfileStore();

const profilesEnabled = useProfilesFeatureEnabled();
const { profilesEnabled } = useProfiles();

const profileAndFavoritesPage = location.pathname?.includes('my-profile') || location.pathname.includes('favorites');

Expand Down
Loading

0 comments on commit 4d85c1c

Please sign in to comment.