Skip to content

Commit

Permalink
Merge pull request #2987 from Hyperkid123/ansible-trial
Browse files Browse the repository at this point in the history
fix ansible bundle trial redirects
  • Loading branch information
Hyperkid123 authored Jan 6, 2025
2 parents a65048d + a452b7c commit 8cb34c7
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/components/Routes/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import LoadingFallback from '../../utils/loading-fallback';
import { useFlag } from '@unleash/proxy-client-react';
import { useAtomValue } from 'jotai';
import { moduleRoutesAtom } from '../../state/atoms/chromeModuleAtom';
import useTrialRedirect from '../../hooks/useTrialRedirect';

const INTEGRATION_SOURCES = 'platform.sources.integrations';

Expand Down Expand Up @@ -69,6 +70,7 @@ const ChromeRoutes = ({ routesProps }: RoutesProps) => {
const featureFlags = useMemo<Record<string, boolean>>(() => ({ INTEGRATION_SOURCES: enableIntegrations }), [enableIntegrations]);
const moduleRoutes = useAtomValue(moduleRoutesAtom);
const showBundleCatalog = localStorage.getItem('chrome:experimental:quickstarts') === 'true';
useTrialRedirect();

return (
<Routes>
Expand Down
107 changes: 107 additions & 0 deletions src/hooks/useTrialRedirect.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React, { PropsWithChildren } from 'react';
import { MemoryRouter, MemoryRouterProps, useLocation } from 'react-router-dom';
import ChromeAuthContext, { ChromeAuthContextValue } from '../auth/ChromeAuthContext';
import { ChromeUser } from '@redhat-cloud-services/types';
import { renderHook, screen } from '@testing-library/react';
import useTrialRedirect from './useTrialRedirect';

const PathnameSpy = () => {
const { pathname } = useLocation();
return <h1 aria-label="pathname-spy">{pathname}</h1>;
};

type WrapperProps = PropsWithChildren<{ chromeAuthContext?: ChromeAuthContextValue; initialEntries?: MemoryRouterProps['initialEntries'] }>;

const RouterWrapper = ({ children, initialEntries = ['/'] }: WrapperProps) => {
return (
<MemoryRouter initialEntries={initialEntries}>
{children}
<PathnameSpy />
</MemoryRouter>
);
};

const defaultChromeUser: ChromeUser = {
entitlements: {},
identity: {},
} as ChromeUser;

const defaultChromeAuthContextValue: ChromeAuthContextValue = {
user: defaultChromeUser,
} as ChromeAuthContextValue;

const ChromeAuthWrapper = ({ children, chromeAuthContext = defaultChromeAuthContextValue, ...rest }: WrapperProps) => {
return (
<ChromeAuthContext.Provider value={chromeAuthContext}>
<RouterWrapper {...rest}>{children}</RouterWrapper>
</ChromeAuthContext.Provider>
);
};

const cases: { entitlements: ChromeUser['entitlements']; expected: string; initialEntries: string[] }[] = [
{
entitlements: {
ansible: {
is_entitled: false,
is_trial: false,
},
},
expected: '/ansible/ansible-dashboard/trial',
initialEntries: ['/ansible/ansible-dashboard/foo/bar'],
},
{
entitlements: {
ansible: {
is_entitled: true,
is_trial: false,
},
},
expected: '/ansible/ansible-dashboard/foo/bar',
initialEntries: ['/ansible/ansible-dashboard/foo/bar'],
},
{
entitlements: {
ansible: {
is_entitled: false,
is_trial: true,
},
},
expected: '/ansible/ansible-dashboard/foo/bar',
initialEntries: ['/ansible/ansible-dashboard/foo/bar'],
},
{
entitlements: {
ansible: {
is_entitled: false,
is_trial: false,
},
},
expected: '/ansible/ansible-dashboard/trial/success',
initialEntries: ['/ansible/ansible-dashboard/trial/success'],
},
];

describe('useTrialRedirect', () => {
cases.forEach(({ entitlements, expected, initialEntries }) => {
test(`should be on ${expected} route based on entitlements`, () => {
renderHook(() => useTrialRedirect(), {
wrapper: (props) => (
<ChromeAuthWrapper
initialEntries={initialEntries}
chromeAuthContext={
{
user: {
...defaultChromeUser,
entitlements,
},
} as ChromeAuthContextValue
}
{...props}
/>
),
});

expect(screen.getByLabelText('pathname-spy')).toHaveTextContent(expected);
});
});
});
42 changes: 42 additions & 0 deletions src/hooks/useTrialRedirect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useContext, useEffect } from 'react';
import ChromeAuthContext from '../auth/ChromeAuthContext';
import { matchPath, useLocation, useNavigate } from 'react-router-dom';
import { ChromeUser } from '@redhat-cloud-services/types';
import { isAnsibleTrialFlagActive } from '../utils/isAnsibleTrialFlagActive';

const ignoredPaths = ['/ansible/trial/*', '/ansible/ansible-dashboard/trial/*'];

const redirects: {
[pattern: string]: {
redirect: string;
entitlementsKey: string;
getTempTrialFlag: () => boolean;
};
} = {
'ansible/*': { redirect: '/ansible/ansible-dashboard/trial', entitlementsKey: 'ansible', getTempTrialFlag: isAnsibleTrialFlagActive },
};

function useTrialRedirect() {
const { user } = useContext(ChromeAuthContext);
const navigate = useNavigate();
const { pathname } = useLocation();

function handleTrialRedirect(pathname: string, entitlements: ChromeUser['entitlements']) {
const isIgnored = ignoredPaths.some((path) => matchPath(path, pathname));
if (isIgnored) {
return;
}
const match = Object.keys(redirects).find((path) => matchPath(path, pathname));
if (match && entitlements[redirects[match].entitlementsKey]) {
const entitlement = entitlements[redirects[match].entitlementsKey];
if (!(entitlement.is_entitled || entitlement.is_trial) && !redirects[match].getTempTrialFlag()) {
navigate(redirects[match].redirect);
}
}
}
useEffect(() => {
handleTrialRedirect(pathname, user.entitlements);
}, [pathname, user.entitlements]);
}

export default useTrialRedirect;
3 changes: 3 additions & 0 deletions src/utils/isAnsibleTrialFlagActive.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logger from '../auth/logger';

// This is needed to "fake" the is_trial entitlement until the backend service catches up. There might be a delay between the activation up to 10 minutes.
export const ANSIBLE_TRIAL_FLAG = 'chrome.ansible.trial';
const TRIAL_DURATION = 10 * 60 * 1000; // 10 minutes

Expand All @@ -20,6 +21,8 @@ export const isAnsibleTrialFlagActive = () => {
log(`Enable to parse ansible trial flag expiration: ${error}`);
}
}

return false;
};

export const setAnsibleTrialFlag = () => {
Expand Down

0 comments on commit 8cb34c7

Please sign in to comment.