Skip to content

Commit

Permalink
feat: project-predictions (#600)
Browse files Browse the repository at this point in the history
Co-authored-by: Noggling <[email protected]>
  • Loading branch information
Noggling and Noggling authored Mar 14, 2024
1 parent 31af4a4 commit bdfd7bb
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/pr-600-1771708999.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

---
"fusion-project-portal": minor
---
Project prediction on landing page
1 change: 1 addition & 0 deletions client/packages/core/src/user/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './useUserInfo';
export * from './userPhoto';
export * from './useUserContexts';
59 changes: 59 additions & 0 deletions client/packages/core/src/user/hooks/useUserContexts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useFramework } from '@equinor/fusion-framework-react';
import { useMemo } from 'react';
import { useQuery } from 'react-query';
import { RelationReturnType, Relations } from '../../context';
import { useCurrentUser } from './useUserInfo';

import { from, lastValueFrom, map, mergeMap, reduce, switchMap } from 'rxjs';

type ID = { id: string };

export const useUserOrgDetails = (viewAll?: boolean) => {
const { data: user } = useCurrentUser();

const serviceProvider = useFramework().modules.serviceDiscovery;

const projects = useMemo(() => {
return user?.positions
?.filter((item) => viewAll || (item.appliesTo && new Date(item.appliesTo) > new Date()))
.map((position) => position.project.id);
}, [user, viewAll]);

return useQuery<RelationReturnType<'ProjectMaster'>[], Error>({
queryKey: ['pro-to-proM ', JSON.stringify(projects?.join), viewAll],
queryFn: async () => {
const contextClient = await serviceProvider.createClient('context');

const gg = contextClient
.json$<ID[]>(
`contexts/?$filter=type eq orgchart and (${projects
?.map((id) => `externalID eq ${id}`)
.join(' or ')})`
)
.pipe(
switchMap((items) =>
from(items).pipe(
mergeMap((item) =>
contextClient
.json$<Relations[]>(`contexts/${item.id}/relations`)
.pipe(
map((x) =>
x.filter((p): p is RelationReturnType<'ProjectMaster'> =>
p.relationSource.includes('ProjectMaster')
)
)
)
),
reduce(
(acc, items) => [...acc, ...items].sort((i, o) => (i.title < o.title ? -1 : 1)),
[] as RelationReturnType<'ProjectMaster'>[]
)
)
)
);
return lastValueFrom(gg);
},
enabled: Boolean(projects && projects?.length > 0),
_defaulted: undefined,
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,13 @@ export function createPortalFramework(portalConfig: PortalConfig) {
{
key: 'new-menu',
title: 'New Portal Menu',
description: 'When enabled you will be able to tryout the new portal menu',
description: 'When enabled you will be able to try out the new portal menu',
enabled: true,
},
{
key: 'project-prediction',
title: 'Project Prediction',
description: 'When enabled you will get project prediction on the project portal landing page',
enabled: true,
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import styled from 'styled-components';
import { User } from './user/UserCard';

import InfoBox from '../sheared/components/InfoBox/InfoBox';
import { useUserOrgDetails } from '@portal/core';
import { Checkbox, LinearProgress, Typography } from '@equinor/eds-core-react';

import { useState } from 'react';
import { useFeature } from '@equinor/fusion-framework-react-app/feature-flag';

const styles = {
contentSection: css`
Expand All @@ -24,9 +29,6 @@ const styles = {
flex-direction: column;
gap: 1rem;
`,
viewDescription: css`
width: 50vw;
`,
};

export const Styles = {
Expand All @@ -35,6 +37,12 @@ export const Styles = {
flex-direction: column;
`,

Section: styled.span`
width: 40vw;
display: flex;
flex-direction: column;
gap: 0.5rem;
`,
Content: styled.section`
padding: 0rem 2rem;
height: 100vh;
Expand Down Expand Up @@ -77,9 +85,39 @@ export const Styles = {
flex: 1;
flex-direction: column;
`,
Heading: styled.div`
padding-top: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
`,
LinkWrapper: styled.span`
display: flex;
align-items: center;
gap: 0.5rem;
`,
Nav: styled.nav`
padding: 1rem 0;
gap: 0.5rem;
display: flex;
flex-wrap: wrap;
width: 25%;
`,
Loading: styled.div`
padding: 1rem 0;
width: 25%;
`,
Padding: styled.span`
padding: 2rem;
`,
};

export const ProjectPortalPage = (): JSX.Element => {
const [value, setValue] = useState(false);
const { data, isLoading } = useUserOrgDetails(value);
const { feature } = useFeature('project-prediction');

return (
<Styles.Wrapper>
<ProjectHeader>
Expand All @@ -89,15 +127,65 @@ export const ProjectPortalPage = (): JSX.Element => {
</Styles.Details>
<Styles.Content>
<div className={styles.contentWrapper}>
<p className={styles.viewDescription}>
Please choose a project or facility from the search field to continue. This will direct you
to the context's homepage, where you can access the applications associated with the
selected context through the menu.
</p>
<Styles.Section>
<Typography>
Please choose a project or facility from the search field to continue. This will direct
you to the context's homepage, where you can access the applications associated with the
selected context through the menu.
</Typography>
</Styles.Section>
<ContextProvider>
<PortalContextSelector />
</ContextProvider>
</div>
{feature?.enabled && (
<Styles.Padding>
<Styles.Section>
<Styles.Heading>
<Typography variant="h5">Allocated Projects</Typography>
<Checkbox
label="Use all past allocations"
checked={value}
onChange={() => {
setValue((s) => !s);
}}
/>
</Styles.Heading>
<Typography>
By analyzing your allocations, we can provide predictions regarding which projects
you may want to prioritize. Here is a list of {value ? 'all your' : 'your current'}{' '}
projects:
</Typography>
</Styles.Section>
{isLoading ? (
<Styles.Loading>
<LinearProgress />
<Typography>Analyzing your allocations...</Typography>
</Styles.Loading>
) : (
<Styles.Nav>
{data && data.length > 0 ? (
data.map((item, index) => (
<Styles.LinkWrapper key={item.id}>
<Typography link title={item.title} href={`/project/${item.id}`}>
{item.title}
</Typography>
{data.length > index + 1 && <span>|</span>}
</Styles.LinkWrapper>
))
) : (
<>
{data && (
<Typography variant="overline">
Sorry, we could not find any projects from your allocations.
</Typography>
)}
</>
)}
</Styles.Nav>
)}
</Styles.Padding>
)}
</Styles.Content>
</ProjectHeader>
</Styles.Wrapper>
Expand Down

0 comments on commit bdfd7bb

Please sign in to comment.