Skip to content

Commit 6c971b2

Browse files
committed
Add Client Referrals page
1 parent 080ccd5 commit 6c971b2

15 files changed

+1145
-110
lines changed

graphql.schema.json

Lines changed: 282 additions & 49 deletions
Large diffs are not rendered by default.

src/api/operations/ce.fragments.graphql

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ fragment CeOpportunityFields on CeOpportunity {
2121
}
2222
}
2323

24+
fragment ClientCeOpportunitySummaryFields on CeOpportunity {
25+
...CeOpportunitySummaryFields
26+
project {
27+
id
28+
projectName
29+
projectType
30+
}
31+
}
32+
2433
fragment CeMatchRuleFields on CeMatchRule {
2534
id
2635
name
@@ -54,6 +63,19 @@ fragment CeReferralTableFields on CeReferral {
5463
name
5564
}
5665
currentStepName
66+
referredBy {
67+
id
68+
name
69+
}
70+
}
71+
72+
fragment ClientCeReferralTableFields on CeReferral {
73+
...CeReferralTableFields
74+
targetProject {
75+
id
76+
projectName
77+
projectType
78+
}
5779
}
5880

5981
fragment CeReferralFields on CeReferral {

src/api/operations/ce.queries.graphql

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ query GetProjectCeOpportunities(
22
$id: ID!
33
$limit: Int = 25
44
$offset: Int = 0
5-
$filters: CeOpportunityFilterOptions = null
5+
$filters: ProjectCeOpportunityFilterOptions = null
66
) {
77
project(id: $id) {
88
id
@@ -21,7 +21,7 @@ query GetProjectCeReferrals(
2121
$id: ID!
2222
$limit: Int = 25
2323
$offset: Int = 0
24-
$filters: CeReferralFilterOptions = null
24+
$filters: ProjectCeReferralFilterOptions = null
2525
) {
2626
project(id: $id) {
2727
id
@@ -71,3 +71,41 @@ query GetCeReferralStep($id: ID!) {
7171
...CeReferralStepFields
7272
}
7373
}
74+
75+
query GetClientCeReferrals(
76+
$id: ID!
77+
$limit: Int = 25
78+
$offset: Int = 0
79+
$filters: CeReferralFilterOptions = null
80+
) {
81+
client(id: $id) {
82+
id
83+
ceReferrals(limit: $limit, offset: $offset, filters: $filters) {
84+
offset
85+
limit
86+
nodesCount
87+
nodes {
88+
...ClientCeReferralTableFields
89+
}
90+
}
91+
}
92+
}
93+
94+
query GetClientEligibleOpportunities(
95+
$id: ID!
96+
$limit: Int = 25
97+
$offset: Int = 0
98+
$filters: ClientEligibleCeOpportunityFilterOptions = null
99+
) {
100+
client(id: $id) {
101+
id
102+
eligibleCeOpportunities(limit: $limit, offset: $offset, filters: $filters) {
103+
offset
104+
limit
105+
nodesCount
106+
nodes {
107+
...ClientCeOpportunitySummaryFields
108+
}
109+
}
110+
}
111+
}

src/modules/ce/components/ProjectOpportunitiesTable.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,30 @@ import {
1313
} from '@/types/gqlTypes';
1414
import { generateSafePath } from '@/utils/pathEncoding';
1515

16-
const COLUMNS: ColumnDef<CeOpportunitySummaryFieldsFragment>[] = [
17-
{
16+
export const OPPORTUNITY_COLUMNS: Record<
17+
string,
18+
ColumnDef<CeOpportunitySummaryFieldsFragment>
19+
> = {
20+
name: {
1821
header: 'Opportunity',
19-
render: 'name',
2022
key: 'name',
2123
sticky: 'left',
24+
render: 'name',
2225
},
23-
{
26+
type: {
2427
header: 'Type',
28+
key: 'type',
2529
render: (row) => {
2630
return row.categories.map((category) => (
2731
<Chip key={category} size='small' variant='outlined' label={category} />
2832
));
2933
},
30-
key: 'type',
3134
},
35+
};
36+
37+
const COLUMNS: ColumnDef<CeOpportunitySummaryFieldsFragment>[] = [
38+
OPPORTUNITY_COLUMNS.name,
39+
OPPORTUNITY_COLUMNS.type,
3240
];
3341

3442
interface Props {}

src/modules/ce/components/ProjectReferralsTable.tsx

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,36 +16,58 @@ import {
1616
} from '@/types/gqlTypes';
1717
import { generateSafePath } from '@/utils/pathEncoding';
1818

19-
const COLUMNS: ColumnDef<CeReferralTableFieldsFragment>[] = [
20-
{
19+
export const REFERRAL_COLUMNS: Record<
20+
string,
21+
ColumnDef<CeReferralTableFieldsFragment>
22+
> = {
23+
client: {
2124
header: 'Client',
22-
render: (referral) => clientNameFromRecordWithOptionalClient(referral),
25+
render: (referral: CeReferralTableFieldsFragment) =>
26+
clientNameFromRecordWithOptionalClient(referral),
2327
key: 'name',
2428
sticky: 'left',
2529
},
26-
{
30+
opportunity: {
2731
header: 'Opportunity',
2832
key: 'opportunity',
29-
render: (referral) => referral.opportunity.name,
33+
render: (referral: CeReferralTableFieldsFragment) =>
34+
referral.opportunity.name,
3035
},
31-
{
32-
header: 'Started',
33-
key: 'started',
34-
render: (referral) => (
36+
date: {
37+
header: 'Referral Date',
38+
key: 'date',
39+
render: (referral: CeReferralTableFieldsFragment) => (
3540
<RelativeDateDisplay dateString={referral.createdAt} />
3641
),
3742
},
38-
{
43+
status: {
3944
header: 'Status',
40-
render: (referral) => <ReferralStatusChip status={referral.status} />,
45+
render: (referral: CeReferralTableFieldsFragment) => (
46+
<ReferralStatusChip status={referral.status} />
47+
),
4148
key: 'status',
4249
},
43-
{
50+
step: {
4451
header: 'Current Step',
4552
key: 'step',
46-
render: (referral) => referral.currentStepName,
53+
render: (referral: CeReferralTableFieldsFragment) =>
54+
referral.currentStepName,
55+
},
56+
referredBy: {
57+
header: 'Referred By',
58+
key: 'referredBy',
59+
render: (referral: CeReferralTableFieldsFragment) =>
60+
referral.referredBy?.name,
4761
},
48-
// TODO(#7321) - add column for sending project here
62+
// TODO(#7321) - add column for sending project
63+
};
64+
65+
const COLUMNS: ColumnDef<CeReferralTableFieldsFragment>[] = [
66+
REFERRAL_COLUMNS.client,
67+
REFERRAL_COLUMNS.opportunity,
68+
REFERRAL_COLUMNS.date,
69+
REFERRAL_COLUMNS.status,
70+
REFERRAL_COLUMNS.step,
4971
];
5072

5173
interface Props {}

src/modules/ce/components/ReferralPage.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import React, { useMemo } from 'react';
55
import { Outlet, useOutletContext } from 'react-router-dom';
66
import ButtonLink from '@/components/elements/ButtonLink';
77
import Loading from '@/components/elements/Loading';
8+
import RouterLink from '@/components/elements/RouterLink';
89
import { DetailsIcon } from '@/components/elements/SemanticIcons';
910
import CommonStickyBar from '@/components/layout/CommonStickyBar';
1011
import {
@@ -16,8 +17,8 @@ import NotFound from '@/components/pages/NotFound';
1617
import useCurrentPath from '@/hooks/useCurrentPath';
1718
import useSafeParams from '@/hooks/useSafeParams';
1819
import ReferralStatusChip from '@/modules/ce/components/ReferralStatusChip';
19-
import { clientNameFromRecordWithOptionalClient } from '@/modules/hmis/hmisUtil';
20-
import { ProjectDashboardRoutes } from '@/routes/routes';
20+
import { clientBriefName } from '@/modules/hmis/hmisUtil';
21+
import { ClientDashboardRoutes, ProjectDashboardRoutes } from '@/routes/routes';
2122
import {
2223
CeReferralFieldsFragment,
2324
useGetCeReferralQuery,
@@ -80,7 +81,17 @@ const ReferralPage: React.FC<Props> = ({}) => {
8081
<Stack direction='row' alignItems='center' gap={0.5}>
8182
<Person sx={{ color: 'grayscale.main' }} />
8283
<Typography variant='body1'>
83-
{clientNameFromRecordWithOptionalClient(referral)}
84+
{referral.client ? (
85+
<RouterLink
86+
to={generateSafePath(ClientDashboardRoutes.REFERRALS, {
87+
clientId: referral.client.id,
88+
})}
89+
>
90+
{clientBriefName(referral.client)}
91+
</RouterLink>
92+
) : (
93+
`Client ${referral.clientId}`
94+
)}
8495
</Typography>
8596
</Stack>
8697
<Typography variant='body1'>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { Paper, Typography } from '@mui/material';
2+
import React from 'react';
3+
import { ColumnDef } from '@/components/elements/table/types';
4+
import useClientDashboardContext from '@/modules/client/hooks/useClientDashboardContext';
5+
import GenericTableWithData from '@/modules/dataFetching/components/GenericTableWithData';
6+
import ProjectTypeChip from '@/modules/hmis/components/ProjectTypeChip';
7+
import { useFilters } from '@/modules/hmis/filterUtil';
8+
import { clientBriefName } from '@/modules/hmis/hmisUtil';
9+
import { ProjectDashboardRoutes } from '@/routes/routes';
10+
import {
11+
ClientCeOpportunitySummaryFieldsFragment,
12+
GetClientEligibleOpportunitiesDocument,
13+
GetClientEligibleOpportunitiesQuery,
14+
GetClientEligibleOpportunitiesQueryVariables,
15+
} from '@/types/gqlTypes';
16+
import { generateSafePath } from '@/utils/pathEncoding';
17+
18+
const COLUMNS: ColumnDef<ClientCeOpportunitySummaryFieldsFragment>[] = [
19+
{
20+
header: 'Project Name',
21+
key: 'projectName',
22+
render: (opportunity: ClientCeOpportunitySummaryFieldsFragment) =>
23+
opportunity.project.projectName,
24+
},
25+
{
26+
header: 'Project Type',
27+
key: 'projectType',
28+
render: (opportunity: ClientCeOpportunitySummaryFieldsFragment) => (
29+
<ProjectTypeChip projectType={opportunity.project.projectType} />
30+
),
31+
},
32+
];
33+
34+
const ClientOpportunitiesTable: React.FC = () => {
35+
const { client } = useClientDashboardContext();
36+
const { id: clientId } = client;
37+
const clientName = clientBriefName(client);
38+
39+
const filters = useFilters({
40+
type: 'ClientEligibleCeOpportunityFilterOptions',
41+
});
42+
43+
return (
44+
<>
45+
<Paper sx={{ p: 2, mb: 2 }}>
46+
<Typography variant='h5' component='h2' pb={1}>
47+
About Eligible Opportunities
48+
</Typography>
49+
<Typography variant='body2'>
50+
{clientName} qualifies for several open positions. These positions are
51+
either not currently matched with a client, or the matching process is
52+
not far enough along to cause problems if cancelled (e.g., it hasn't
53+
reached the CoC Initial Review stage). Activating a match for any of
54+
these positions will cancel any existing match for that position,
55+
returning the client to the pool of available candidates. However,
56+
this action will not affect any other matches {clientName} may already
57+
have.
58+
</Typography>
59+
</Paper>
60+
<Paper>
61+
<GenericTableWithData<
62+
GetClientEligibleOpportunitiesQuery,
63+
GetClientEligibleOpportunitiesQueryVariables,
64+
ClientCeOpportunitySummaryFieldsFragment
65+
>
66+
columns={COLUMNS}
67+
queryVariables={{
68+
id: clientId,
69+
}}
70+
filters={filters}
71+
queryDocument={GetClientEligibleOpportunitiesDocument}
72+
pagePath='client.eligibleCeOpportunities'
73+
noData='No opportunities'
74+
paginationItemName='opportunities'
75+
rowLinkTo={(opportunity) =>
76+
generateSafePath(ProjectDashboardRoutes.OPPORTUNITY, {
77+
projectId: opportunity.projectId,
78+
opportunityId: opportunity.id,
79+
})
80+
}
81+
rowActionTitle='View Opportunity'
82+
/>
83+
</Paper>
84+
</>
85+
);
86+
};
87+
88+
export default ClientOpportunitiesTable;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from 'react';
2+
import CommonTabs from '@/components/elements/CommonTabs';
3+
import PageTitle from '@/components/layout/PageTitle';
4+
import ClientOpportunitiesTable from '@/modules/ce/components/client/ClientOpportunitiesTable';
5+
import ClientReferralsTable from '@/modules/ce/components/client/ClientReferralsTable';
6+
7+
const ClientReferralsPage: React.FC = () => {
8+
return (
9+
<>
10+
<PageTitle title={'Referrals'} />
11+
12+
<CommonTabs
13+
ariaLabel={'Client Referrals Tabs'}
14+
tabDefinitions={[
15+
{
16+
title: 'All Referrals',
17+
key: 'referrals',
18+
contents: <ClientReferralsTable />,
19+
},
20+
{
21+
title: 'Eligible Opportunities',
22+
key: 'opportunities',
23+
contents: <ClientOpportunitiesTable />,
24+
},
25+
]}
26+
/>
27+
</>
28+
);
29+
};
30+
31+
export default ClientReferralsPage;

0 commit comments

Comments
 (0)