Skip to content

Commit

Permalink
Merge branch 'feat/homepage-app-improvements' of github.com:EyeSeeTea…
Browse files Browse the repository at this point in the history
…/home-page-app-dev into feat/homepage-app-improvements
  • Loading branch information
p3rcypj committed Jun 2, 2024
2 parents b23f3a8 + a8c423f commit 8f00384
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 38 deletions.
27 changes: 17 additions & 10 deletions src/domain/entities/LandingNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { TranslatableText, TranslatableTextModel } from "./TranslatableText";
import { LandingPagePermission } from "./Permission";
import { User } from "./User";
import { Action, getPageActions } from "./Action";
import { Maybe } from "../../types/utils";

export const LandingPageNodeTypeModel = Schema.oneOf([
Schema.exact("root"),
Expand Down Expand Up @@ -117,42 +118,48 @@ const applyFavicon = (parent: LandingNode): LandingNode => {
};
};

/* Return a redirect URL if there is only one visible action on primary nodes */
export function getPrimaryRedirectUrl(
// Return
// a redirect URL if there is only one visible action on primary nodes
// a redirect page id when there is only one visible action on primary nodes
export function getPrimaryRedirectNodes(
landingNode: LandingNode,
options: { actions: Action[]; user: User }
): Url | undefined {
): { redirectUrl: Maybe<Url>; redirectPageId: Maybe<string> } {
const { actions, user } = options;

const actionsById = _.keyBy(actions, action => action.id);
const showAllActions = false;
const isRoot = true;

const primaryUrls = _(landingNode.children)
const pageActions = _(landingNode.children)
.reject(node => Boolean(node.secondary))
.flatMap((node): Url[] => {
.flatMap((node): Action[] => {
const nodeActions = actions.filter(action => node.actions.includes(action.id));
const actionIds = user && getPageActions(isRoot, showAllActions, actions, user, nodeActions);

return _(actionIds)
.map(actionId => actionsById[actionId])
.compact()
.map(action => action.dhisLaunchUrl)
.compact()
.value();
})
.value();

const redirectUrl = primaryUrls.length === 1 ? primaryUrls[0] : undefined;
const launchUrls = _.map(pageActions, action => action.dhisLaunchUrl);
const launchPageIds = _.map(pageActions, action => action.launchPageId);

const redirectUrl = launchUrls.length === 1 ? launchUrls[0] : undefined;
const redirectPageId = launchPageIds.length === 1 ? launchPageIds[0] : undefined;

const message = [
`Primary URLs [${primaryUrls.length}]: ${primaryUrls.join(", ")}`,
`Primary URLs [${launchUrls.length}]: ${launchUrls.join(", ")}`,
`Redirect URL: ${redirectUrl || "-"}`,
`Primary Page IDs [${launchPageIds.length}]: ${launchPageIds.join(", ")}`,
`Redirect Page ID: ${redirectPageId || "-"}`,
].join("\n");

console.debug(message);

return redirectUrl;
return { redirectUrl, redirectPageId };
}

export function flattenLandingNodes(nodes: LandingNode[]): LandingNode[] {
Expand Down
86 changes: 58 additions & 28 deletions src/webapp/pages/home/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useSnackbar } from "@eyeseetea/d2-ui-components";
import {
LandingNode,
flattenLandingNodes,
getPrimaryRedirectUrl as getPrimaryActionUrl,
getPrimaryRedirectNodes as getPrimaryActionNodes,
} from "../../../domain/entities/LandingNode";
import { LandingLayout, LandingContent } from "../../components/landing-layout";
import { useAppContext } from "../../contexts/app-context";
Expand Down Expand Up @@ -42,7 +42,10 @@ export const HomePage: React.FC = React.memo(() => {
return history[0] ?? initLandings?.[0];
}, [history, initLandings]);

const isRoot = history.length === 0;
const isRoot = _.isEmpty(history);
const isRootPage = currentPage?.type === "root";
const isSingleLanding = pageType === "singleLanding";
const hasSingleInitLanding = initLandings?.length === 1;
const currentHistory = history[0];

const openSettings = useCallback(() => {
Expand All @@ -67,17 +70,24 @@ export const HomePage: React.FC = React.memo(() => {
);

const goBack = useCallback(() => {
if (currentPage?.type === "root" && _.every(history, landing => landing.id === currentPage.id)) {
const allHistoryMatchesCurrentPage = _.every(history, landing => landing.id === currentPage?.id);

if (isRootPage && allHistoryMatchesCurrentPage) {
updateHistory([]);
setPageType("userLandings");
} else if (
initLandings?.length === 1 ||
currentPage?.type !== "root" ||
(currentPage?.type === "root" && !_.isEmpty(history))
) {
} else if (hasSingleInitLanding || !isRootPage || !isRoot) {
updateHistory(history => history.slice(1));
} else setPageType("userLandings");
}, [currentPage, history, initLandings?.length]);
} else {
setPageType("userLandings");
}
}, [currentPage, hasSingleInitLanding, history, isRoot, isRootPage]);

const allowBackNavigation = useMemo(() => {
const isMultipleLandingSubPage = !isRoot && initLandings !== undefined && initLandings.length > 1;
const isSingleLandingSubPage = initLandings?.length === 1 && history.length > 1;

return isSingleLanding && (isMultipleLandingSubPage || isSingleLandingSubPage);
}, [history, initLandings, isRoot, isSingleLanding]);

const goHome = useCallback(() => {
if (initLandings?.length === 1) updateHistory([]);
Expand All @@ -98,6 +108,12 @@ export const HomePage: React.FC = React.memo(() => {
}, 8000);
}, [compositionRoot]);

useEffect(() => {
if (isSingleLanding && hasSingleInitLanding && isRootPage && isRoot) {
updateHistory(history => [currentPage, ...history]);
}
}, [currentPage, hasSingleInitLanding, isRoot, isRootPage, isSingleLanding]);

useEffect(() => {
if (initLandings?.length === 0) {
window.location.href = !defaultApplication
Expand All @@ -113,38 +129,39 @@ export const HomePage: React.FC = React.memo(() => {
const icon = favicon.current;
const pageFavicon = currentPage?.favicon;

icon?.setAttribute("href", (pageType === "singleLanding" && pageFavicon) || defaultIcon);
document.title = (pageType === "singleLanding" && currentPage && translate(currentPage.name)) || defaultTitle;
icon?.setAttribute("href", (isSingleLanding && pageFavicon) || defaultIcon);
document.title = (isSingleLanding && currentPage && translate(currentPage.name)) || defaultTitle;
return () => {
icon?.setAttribute("href", defaultIcon);
document.title = defaultTitle;
};
}, [reload, currentPage, pageType, translate]);
}, [reload, currentPage, isSingleLanding, translate]);

useEffect(() => {
if (userLandings && userLandings?.length > 1 && pageType === "userLandings") {
analytics.sendPageView({
title: "Homepage - Available Home Pages",
location: `${window.location.hash.split("?")[0]}home-page-app/available-landings`,
});
} else if (currentPage && pageType === "singleLanding" && currentHistory) {
const type = currentPage.type === "root" ? "landing" : currentPage.type;
} else if (currentPage && isSingleLanding && currentHistory) {
const type = isRootPage ? "landing" : currentPage.type;
analytics.sendPageView({
title: `Homepage - ${currentPage.name.referenceValue}`,
location: `${window.location.hash.split("?")[0]}home-page-app/${type}/${currentPage.id}`,
});
}
}, [currentPage, analytics, pageType, userLandings, currentHistory]);
}, [analytics, currentHistory, currentPage, isRootPage, isSingleLanding, pageType, userLandings]);

const redirect = useRedirectOnSinglePrimaryAction(currentPage, userLandings);
const redirect = useRedirectOnSinglePrimaryNode(currentPage, userLandings);
const pageToRender = redirect.currentPage || (currentPage && isSingleLanding ? currentPage : undefined);

return (
<StyledLanding
backgroundColor={currentPage?.backgroundColor}
onSettings={hasSettingsAccess ? openSettings : undefined}
onAbout={openAbout}
onGoBack={!isRoot && pageType === "singleLanding" ? goBack : undefined}
onGoHome={!isRoot && pageType === "singleLanding" ? goHome : undefined}
onGoBack={allowBackNavigation ? goBack : undefined}
onGoHome={!isRoot && isSingleLanding ? goHome : undefined}
onLogout={logout}
centerChildren={true}
>
Expand Down Expand Up @@ -182,8 +199,8 @@ export const HomePage: React.FC = React.memo(() => {
})}
</Cardboard>
</>
) : currentPage && pageType === "singleLanding" ? (
<Item isRoot={isRoot} currentPage={currentPage} openPage={openPage} />
) : pageToRender ? (
<Item isRoot={isRoot} currentPage={pageToRender} openPage={openPage} />
) : null}
</ContentWrapper>
</StyledLanding>
Expand All @@ -210,25 +227,38 @@ const ContentWrapper = styled.div`
min-height: 100vh;
`;

function useRedirectOnSinglePrimaryAction(
function useRedirectOnSinglePrimaryNode(
landingNode: Maybe<LandingNode>,
userLandings: Maybe<LandingNode[]>
): { isActive: boolean } {
): { isActive: boolean; currentPage: Maybe<LandingNode> } {
const { actions, launchAppBaseUrl } = useAppContext();
const { user } = useConfig();
const url =
user && landingNode && userLandings?.length === 1
? getPrimaryActionUrl(landingNode, { actions, user })
? getPrimaryActionNodes(landingNode, { actions, user })
: undefined;

const [isActive, setIsActive] = React.useState(false);
const [currentPage, setCurrentPage] = React.useState<LandingNode | undefined>();

React.useEffect(() => {
if (url) {
goTo(url, { baseUrl: launchAppBaseUrl });
setIsActive(true);
const { redirectPageId, redirectUrl } = url;
if (redirectUrl && redirectPageId) {
return;
}
if (redirectUrl) {
goTo(redirectUrl, { baseUrl: launchAppBaseUrl });
setIsActive(true);
}
if (redirectPageId) {
const page = userLandings?.find(landing => landing.id === redirectPageId);
if (page) {
setCurrentPage(page);
}
}
}
}, [url, launchAppBaseUrl]);
}, [url, launchAppBaseUrl, userLandings]);

return { isActive };
return { isActive: isActive, currentPage: currentPage };
}

0 comments on commit 8f00384

Please sign in to comment.