eionet2-dashboard 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.fx/configs/azure.parameters.Prod_EEA.json +15 -0
- package/.fx/configs/azure.parameters.dev.json +15 -0
- package/.fx/configs/config.Prod_EEA.json +10 -0
- package/.fx/configs/config.dev.json +10 -0
- package/.fx/configs/projectSettings.json +83 -0
- package/.fx/states/state.Prod_EEA.json +47 -0
- package/.fx/states/state.dev.json +47 -0
- package/.vscode/launch.json +91 -0
- package/.vscode/settings.json +6 -0
- package/.vscode/tasks.json +63 -0
- package/CHANGELOG.md +140 -0
- package/Jenkinsfile +166 -0
- package/LICENSE.md +9 -0
- package/README.md +55 -0
- package/api/.funcignore +11 -0
- package/api/extensions.csproj +11 -0
- package/api/getGraphData/function.json +27 -0
- package/api/getGraphData/index.js +147 -0
- package/api/host.json +11 -0
- package/api/package-lock.json +1546 -0
- package/api/package.json +17 -0
- package/api/proxies.json +4 -0
- package/package.json +25 -0
- package/tabs/.env.teamsfx.Prod_EEA +11 -0
- package/tabs/.env.teamsfx.dev +11 -0
- package/tabs/.eslintrc.json +48 -0
- package/tabs/.prettierrc +7 -0
- package/tabs/.stylelintrc.json +6 -0
- package/tabs/babel.config.js +3 -0
- package/tabs/package-lock.json +15564 -0
- package/tabs/package.json +88 -0
- package/tabs/public/auth-end.html +76 -0
- package/tabs/public/auth-start.html +178 -0
- package/tabs/public/deploy.png +0 -0
- package/tabs/public/favicon.ico +0 -0
- package/tabs/public/hello.png +0 -0
- package/tabs/public/index.html +20 -0
- package/tabs/public/publish.png +0 -0
- package/tabs/src/components/App.jsx +36 -0
- package/tabs/src/components/CustomColumnResizeIcon.jsx +68 -0
- package/tabs/src/components/CustomDrawer.jsx +51 -0
- package/tabs/src/components/EventDialogTitle.jsx +29 -0
- package/tabs/src/components/HtmlBox.jsx +18 -0
- package/tabs/src/components/Privacy.jsx +17 -0
- package/tabs/src/components/ResizableGrid.jsx +44 -0
- package/tabs/src/components/Tab.jsx +477 -0
- package/tabs/src/components/Tab.scss +138 -0
- package/tabs/src/components/TabConfig.jsx +51 -0
- package/tabs/src/components/TabPanel.jsx +29 -0
- package/tabs/src/components/TermsOfUse.jsx +17 -0
- package/tabs/src/components/UnderConstruction.jsx +24 -0
- package/tabs/src/components/UserMenu.jsx +109 -0
- package/tabs/src/components/_variables.scss +10 -0
- package/tabs/src/components/activity/Activity.jsx +301 -0
- package/tabs/src/components/activity/ConsultationList.jsx +297 -0
- package/tabs/src/components/activity/EventList.jsx +463 -0
- package/tabs/src/components/activity/GroupsTags.jsx +26 -0
- package/tabs/src/components/activity/Reporting.jsx +13 -0
- package/tabs/src/components/activity/activity.scss +153 -0
- package/tabs/src/components/event_rating/EventRating.jsx +92 -0
- package/tabs/src/components/event_rating/EventRatingDialog.jsx +46 -0
- package/tabs/src/components/event_registration/Approval.jsx +80 -0
- package/tabs/src/components/event_registration/ApprovalDialog.jsx +30 -0
- package/tabs/src/components/event_registration/ApprovalList.jsx +62 -0
- package/tabs/src/components/event_registration/EventRegistration.jsx +214 -0
- package/tabs/src/components/lib/useData.js +33 -0
- package/tabs/src/components/lib/useGraph.js +39 -0
- package/tabs/src/components/lib/useTeamsFx.js +55 -0
- package/tabs/src/components/my_country/AtAGlance.jsx +151 -0
- package/tabs/src/components/my_country/CountryProgress.jsx +92 -0
- package/tabs/src/components/my_country/DataReporters.jsx +13 -0
- package/tabs/src/components/my_country/GroupView.jsx +54 -0
- package/tabs/src/components/my_country/GroupsBoard.jsx +52 -0
- package/tabs/src/components/my_country/IndicatorCard.jsx +60 -0
- package/tabs/src/components/my_country/ManagementBoard.jsx +109 -0
- package/tabs/src/components/my_country/MyCountry.jsx +186 -0
- package/tabs/src/components/my_country/ProgressGauge.jsx +125 -0
- package/tabs/src/components/my_country/ScientificCommittee.jsx +13 -0
- package/tabs/src/components/my_country/YearlyProgress.jsx +41 -0
- package/tabs/src/components/my_country/my_country.scss +81 -0
- package/tabs/src/components/publications/Publications.jsx +13 -0
- package/tabs/src/components/self_service/UserEdit.jsx +334 -0
- package/tabs/src/components/self_service/UserEdit.scss +107 -0
- package/tabs/src/data/apiProvider.js +153 -0
- package/tabs/src/data/constants.json +7 -0
- package/tabs/src/data/hooks/useConfiguration.js +18 -0
- package/tabs/src/data/icsHelper.js +38 -0
- package/tabs/src/data/messages.json +39 -0
- package/tabs/src/data/provider.js +199 -0
- package/tabs/src/data/selfServiceProvider.js +59 -0
- package/tabs/src/data/selfServiceSharepointProvider.js +68 -0
- package/tabs/src/data/sharepointProvider.js +729 -0
- package/tabs/src/data/validator.js +25 -0
- package/tabs/src/data/validator.test.js +9 -0
- package/tabs/src/index.css +16 -0
- package/tabs/src/index.jsx +6 -0
- package/tabs/src/static/images/teams-icon.svg +1 -0
- package/tabs/src/utils/uiHelper.js +6 -0
- package/templates/appPackage/aad.template.json +133 -0
- package/templates/appPackage/manifest.template.json +58 -0
- package/templates/appPackage/resources/color.png +0 -0
- package/templates/appPackage/resources/outline.png +0 -0
- package/templates/azure/config.bicep +27 -0
- package/templates/azure/main.bicep +20 -0
- package/templates/azure/provision/frontendHosting.bicep +23 -0
- package/templates/azure/provision/function.bicep +82 -0
- package/templates/azure/provision/identity.bicep +14 -0
- package/templates/azure/provision/simpleAuth.bicep +44 -0
- package/templates/azure/provision.bicep +58 -0
- package/templates/azure/teamsFx/function.bicep +76 -0
- package/templates/azure/teamsFx/simpleAuth.bicep +43 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { React, useState, useEffect } from 'react';
|
|
2
|
+
import { Box, Typography, Backdrop, CircularProgress } from '@mui/material';
|
|
3
|
+
import { IndicatorCard } from './IndicatorCard';
|
|
4
|
+
import { CountryProgress } from './CountryProgress';
|
|
5
|
+
import { getGroups } from '../../data/sharepointProvider';
|
|
6
|
+
import { HtmlBox } from '../HtmlBox';
|
|
7
|
+
import { getMeetings, getConsultations } from '../../data/sharepointProvider';
|
|
8
|
+
|
|
9
|
+
export function AtAGlance({
|
|
10
|
+
users,
|
|
11
|
+
organisations,
|
|
12
|
+
country,
|
|
13
|
+
userInfo,
|
|
14
|
+
configuration,
|
|
15
|
+
availableGroups,
|
|
16
|
+
}) {
|
|
17
|
+
const signedInUsers = users.filter((u) => {
|
|
18
|
+
return u.SignedIn;
|
|
19
|
+
}),
|
|
20
|
+
signedInGroups = getGroups(signedInUsers),
|
|
21
|
+
pendingSignInUsers = users.filter((u) => {
|
|
22
|
+
return !u.SignedIn;
|
|
23
|
+
}),
|
|
24
|
+
pendingSignInGroups = getGroups(pendingSignInUsers),
|
|
25
|
+
nominationsGroups = [...new Set(signedInGroups.concat(pendingSignInGroups))],
|
|
26
|
+
countryFilterSuffix = country ? '?FilterField1=Country&FilterValue1=' + country + '&' : '?';
|
|
27
|
+
|
|
28
|
+
const [lastYears, setLastYears] = useState([]),
|
|
29
|
+
[loading, setLoading] = useState(false);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
const fetchData = async () => {
|
|
33
|
+
setLoading(true);
|
|
34
|
+
|
|
35
|
+
//get meetings from last two years
|
|
36
|
+
const fromDate = new Date(new Date().getFullYear() - 2, 0, 1);
|
|
37
|
+
let loadedMeetings = await getMeetings(fromDate, country, userInfo),
|
|
38
|
+
loadedConsultations = await getConsultations(undefined, fromDate);
|
|
39
|
+
|
|
40
|
+
const current = new Date().getFullYear();
|
|
41
|
+
let years = [];
|
|
42
|
+
for (let i = current; i >= current - 1; i--) {
|
|
43
|
+
const allMeetings = loadedMeetings.filter((m) => m.Year == i),
|
|
44
|
+
allConsultations = loadedConsultations.filter(
|
|
45
|
+
(c) => c.Year == i && c.ConsultationType == 'Consultation',
|
|
46
|
+
),
|
|
47
|
+
allSurveys = loadedConsultations.filter(
|
|
48
|
+
(c) => c.Year == i && c.ConsultationType == 'Inquiry',
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const result = {
|
|
52
|
+
year: i,
|
|
53
|
+
meetingsCount: allMeetings.length,
|
|
54
|
+
consultationsCount: allConsultations.length,
|
|
55
|
+
surveysCount: allSurveys.length,
|
|
56
|
+
attendedMeetingsCount: allMeetings.filter((meeting) => {
|
|
57
|
+
return meeting.Participants.some((participant) => participant.Country == country);
|
|
58
|
+
}).length,
|
|
59
|
+
responseConsultationsCount: allConsultations.filter((c) => {
|
|
60
|
+
return c.Respondants.includes(country);
|
|
61
|
+
}).length,
|
|
62
|
+
responseSurveysCount: allSurveys.filter((c) => {
|
|
63
|
+
return c.Respondants.includes(country);
|
|
64
|
+
}).length,
|
|
65
|
+
};
|
|
66
|
+
years.push(result);
|
|
67
|
+
}
|
|
68
|
+
setLastYears(years);
|
|
69
|
+
setLoading(false);
|
|
70
|
+
};
|
|
71
|
+
fetchData();
|
|
72
|
+
}, [country, userInfo]);
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div className="">
|
|
76
|
+
<Box
|
|
77
|
+
sx={{
|
|
78
|
+
height: '100%',
|
|
79
|
+
overflowX: 'hidden',
|
|
80
|
+
}}
|
|
81
|
+
>
|
|
82
|
+
<Backdrop
|
|
83
|
+
sx={{ color: '#6b32a8', zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
|
84
|
+
open={loading}
|
|
85
|
+
>
|
|
86
|
+
<CircularProgress color="primary" />
|
|
87
|
+
</Backdrop>
|
|
88
|
+
<Typography
|
|
89
|
+
sx={{ fontSize: '16px', fontWeight: '600', pt: '12px', pl: '12px' }}
|
|
90
|
+
color="text.secondary"
|
|
91
|
+
>
|
|
92
|
+
Representation:
|
|
93
|
+
</Typography>
|
|
94
|
+
<Box className="cards-container" sx={{ border: '0px' }}>
|
|
95
|
+
<IndicatorCard
|
|
96
|
+
labelText="members"
|
|
97
|
+
valueText={users.length}
|
|
98
|
+
url={configuration.UserListUrl + countryFilterSuffix}
|
|
99
|
+
infoText={configuration.NoOfMembersCardInfo}
|
|
100
|
+
></IndicatorCard>
|
|
101
|
+
<IndicatorCard
|
|
102
|
+
labelText="members pending sign in"
|
|
103
|
+
valueText={users.length - signedInUsers.length}
|
|
104
|
+
url={
|
|
105
|
+
configuration.UserListUrl +
|
|
106
|
+
countryFilterSuffix +
|
|
107
|
+
'FilterField2=SignedIn&FilterValue2=0'
|
|
108
|
+
}
|
|
109
|
+
infoText={configuration.MembersPendingSingInCardInfo}
|
|
110
|
+
></IndicatorCard>
|
|
111
|
+
<IndicatorCard
|
|
112
|
+
labelText="organisations"
|
|
113
|
+
valueText={organisations.length}
|
|
114
|
+
url={configuration.OrganisationListUrl + countryFilterSuffix}
|
|
115
|
+
infoText={configuration.NoOfOrganisationsCardInfo}
|
|
116
|
+
></IndicatorCard>
|
|
117
|
+
<IndicatorCard
|
|
118
|
+
labelText="groups with nominations"
|
|
119
|
+
valueText={nominationsGroups.length + '/' + availableGroups.length}
|
|
120
|
+
infoText={configuration.GroupsWithNominationsCardInfo}
|
|
121
|
+
></IndicatorCard>
|
|
122
|
+
<IndicatorCard
|
|
123
|
+
labelText="groups with signed in users"
|
|
124
|
+
valueText={signedInGroups.length + '/' + availableGroups.length}
|
|
125
|
+
infoText={configuration.GroupsWithSignedInUsersCardInfo}
|
|
126
|
+
></IndicatorCard>
|
|
127
|
+
</Box>
|
|
128
|
+
{country && (
|
|
129
|
+
<Box sx={{ marginLeft: '1rem' }}>
|
|
130
|
+
<HtmlBox html={configuration.CountryProgressHtml}></HtmlBox>
|
|
131
|
+
</Box>
|
|
132
|
+
)}
|
|
133
|
+
{country && (
|
|
134
|
+
<Box
|
|
135
|
+
sx={{
|
|
136
|
+
display: 'flex',
|
|
137
|
+
flexDirection: 'column',
|
|
138
|
+
width: '100%',
|
|
139
|
+
flexGrow: 1,
|
|
140
|
+
marginLeft: '1rem',
|
|
141
|
+
borderTop: 1,
|
|
142
|
+
borderColor: 'divider',
|
|
143
|
+
}}
|
|
144
|
+
>
|
|
145
|
+
<CountryProgress lastYears={lastYears} configuration={configuration}></CountryProgress>
|
|
146
|
+
</Box>
|
|
147
|
+
)}
|
|
148
|
+
</Box>
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { React, useState } from 'react';
|
|
2
|
+
import { Box, Typography, Tab, Tabs } from '@mui/material';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import { YearlyProgress } from './YearlyProgress';
|
|
5
|
+
function TabPanel(props) {
|
|
6
|
+
const { children, value, index, ...other } = props;
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<div
|
|
10
|
+
role="tabpanel"
|
|
11
|
+
hidden={value !== index}
|
|
12
|
+
id={`simple-tabpanel-${index}`}
|
|
13
|
+
aria-labelledby={`simple-tab-${index}`}
|
|
14
|
+
{...other}
|
|
15
|
+
>
|
|
16
|
+
{value === index && (
|
|
17
|
+
<Box sx={{ pt: 1, borderTop: 1, borderColor: 'secondary.main' }}>
|
|
18
|
+
<Typography component={'span'}>{children}</Typography>
|
|
19
|
+
</Box>
|
|
20
|
+
)}
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
TabPanel.propTypes = {
|
|
26
|
+
children: PropTypes.node,
|
|
27
|
+
index: PropTypes.number.isRequired,
|
|
28
|
+
value: PropTypes.number.isRequired,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function a11yProps(index) {
|
|
32
|
+
return {
|
|
33
|
+
id: `simple-tab-${index}`,
|
|
34
|
+
'aria-controls': `simple-tabpanel-${index}`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function CountryProgress({ lastYears, configuration }) {
|
|
39
|
+
const [tabsValue, setTabsValue] = useState(0),
|
|
40
|
+
handleChange = (_event, newValue) => {
|
|
41
|
+
setTabsValue(newValue);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className="">
|
|
46
|
+
{lastYears.length > 0 && (
|
|
47
|
+
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
|
48
|
+
<Typography
|
|
49
|
+
sx={{ fontSize: '16px', fontWeight: '600', paddingTop: '12px' }}
|
|
50
|
+
color="text.secondary"
|
|
51
|
+
>
|
|
52
|
+
Yearly overview:
|
|
53
|
+
</Typography>
|
|
54
|
+
<Tabs
|
|
55
|
+
TabIndicatorProps={{
|
|
56
|
+
sx: {
|
|
57
|
+
bottom: 0,
|
|
58
|
+
height: 10,
|
|
59
|
+
backgroundColor: 'secondary.main',
|
|
60
|
+
clipPath: 'polygon(50% 0, 0 100%, 100% 100%)',
|
|
61
|
+
},
|
|
62
|
+
}}
|
|
63
|
+
value={tabsValue}
|
|
64
|
+
onChange={handleChange}
|
|
65
|
+
>
|
|
66
|
+
{lastYears.map((year, index) => {
|
|
67
|
+
return (
|
|
68
|
+
<Tab className="year-tab" key={index} label={year.year} {...a11yProps(index)} />
|
|
69
|
+
);
|
|
70
|
+
})}
|
|
71
|
+
</Tabs>
|
|
72
|
+
{lastYears.map((year, index) => {
|
|
73
|
+
return (
|
|
74
|
+
<TabPanel className="year-panel" key={index} value={tabsValue} index={index}>
|
|
75
|
+
<YearlyProgress
|
|
76
|
+
allMeetingsCount={year.meetingsCount}
|
|
77
|
+
allConsultationsCount={year.consultationsCount}
|
|
78
|
+
allSurveysCount={year.surveysCount}
|
|
79
|
+
attendedMeetingsCount={year.attendedMeetingsCount}
|
|
80
|
+
responseConsultationsCount={year.responseConsultationsCount}
|
|
81
|
+
responseSurveysCount={year.responseSurveysCount}
|
|
82
|
+
year={year.year}
|
|
83
|
+
configuration={configuration}
|
|
84
|
+
></YearlyProgress>
|
|
85
|
+
</TabPanel>
|
|
86
|
+
);
|
|
87
|
+
})}
|
|
88
|
+
</Box>
|
|
89
|
+
)}
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { React } from 'react';
|
|
2
|
+
import { Box } from '@mui/material';
|
|
3
|
+
import { UnderConstruction } from '../UnderConstruction';
|
|
4
|
+
|
|
5
|
+
export function DataReporters() {
|
|
6
|
+
return (
|
|
7
|
+
<div className="">
|
|
8
|
+
<Box className="box-fill">
|
|
9
|
+
<UnderConstruction></UnderConstruction>
|
|
10
|
+
</Box>
|
|
11
|
+
</div>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { React } from 'react';
|
|
2
|
+
import './my_country.scss';
|
|
3
|
+
import ResizableGrid from '../ResizableGrid';
|
|
4
|
+
import { Box } from '@mui/material';
|
|
5
|
+
|
|
6
|
+
export function GroupView({ group }) {
|
|
7
|
+
const columns = [
|
|
8
|
+
{
|
|
9
|
+
field: 'Organisation',
|
|
10
|
+
headerName: 'Organisation',
|
|
11
|
+
flex: 1.5,
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
field: 'Title',
|
|
15
|
+
headerName: 'Name',
|
|
16
|
+
flex: 0.75,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
field: 'Email',
|
|
20
|
+
headerName: 'Email',
|
|
21
|
+
flex: 0.75,
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
return (
|
|
25
|
+
<Box
|
|
26
|
+
sx={{
|
|
27
|
+
display: 'flex',
|
|
28
|
+
height: '98%',
|
|
29
|
+
width: '100%',
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
{group && (
|
|
33
|
+
<ResizableGrid
|
|
34
|
+
id={group.GroupName}
|
|
35
|
+
rows={group.Users}
|
|
36
|
+
columns={columns}
|
|
37
|
+
hideFooterSelectedRowCount
|
|
38
|
+
pageSizeOptions={[25, 50, 100]}
|
|
39
|
+
initialState={{
|
|
40
|
+
pagination: { paginationModel: { pageSize: 25 } },
|
|
41
|
+
sorting: {
|
|
42
|
+
sortModel: [
|
|
43
|
+
{
|
|
44
|
+
field: 'Organisation',
|
|
45
|
+
sort: 'asc',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
}}
|
|
50
|
+
/>
|
|
51
|
+
)}
|
|
52
|
+
</Box>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { React, useState } from 'react';
|
|
2
|
+
import { Box, ListItem, ListItemButton, ListItemText } from '@mui/material';
|
|
3
|
+
import { GroupView } from './GroupView';
|
|
4
|
+
import CustomDrawer from '../CustomDrawer';
|
|
5
|
+
|
|
6
|
+
export function GroupsBoard({ users, mappings }) {
|
|
7
|
+
const [groupIndex, setGroupIndex] = useState(0),
|
|
8
|
+
groups = mappings
|
|
9
|
+
.map((m) => {
|
|
10
|
+
const filteredUsers = users.filter((user) => {
|
|
11
|
+
return user.AllMemberships.includes(m.Membership);
|
|
12
|
+
});
|
|
13
|
+
return {
|
|
14
|
+
GroupName: m.Membership,
|
|
15
|
+
Users: filteredUsers,
|
|
16
|
+
};
|
|
17
|
+
})
|
|
18
|
+
.filter((group) => group.Users.length > 0),
|
|
19
|
+
drawerOptions = (
|
|
20
|
+
<div>
|
|
21
|
+
{groups.map((currentGroup, index) => {
|
|
22
|
+
return (
|
|
23
|
+
<ListItem disablePadding className="list-item" key={index}>
|
|
24
|
+
<ListItemButton
|
|
25
|
+
className={
|
|
26
|
+
'list-item-button ' + (groupIndex == index ? ' drawer-item-selected' : '')
|
|
27
|
+
}
|
|
28
|
+
onClick={() => setGroupIndex(index)}
|
|
29
|
+
>
|
|
30
|
+
<ListItemText primary={currentGroup.GroupName} />
|
|
31
|
+
</ListItemButton>
|
|
32
|
+
</ListItem>
|
|
33
|
+
);
|
|
34
|
+
})}
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<Box
|
|
40
|
+
sx={{
|
|
41
|
+
overflowY: 'scroll',
|
|
42
|
+
display: 'flex',
|
|
43
|
+
width: '100%',
|
|
44
|
+
height: '98%',
|
|
45
|
+
background: 'white',
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
<CustomDrawer drawerOptions={drawerOptions}></CustomDrawer>
|
|
49
|
+
<GroupView group={groups[groupIndex]}></GroupView>
|
|
50
|
+
</Box>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { React, useState } from 'react';
|
|
2
|
+
import { Typography, Card, CardContent, Dialog, Link, Button, IconButton } from '@mui/material';
|
|
3
|
+
import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
|
|
4
|
+
|
|
5
|
+
export function IndicatorCard({ labelText, valueText, url, infoText }) {
|
|
6
|
+
const [infoOpen, setInfoOpen] = useState(false),
|
|
7
|
+
handleInfoOpen = () => {
|
|
8
|
+
infoText && setInfoOpen(true);
|
|
9
|
+
},
|
|
10
|
+
handleInfoClose = () => {
|
|
11
|
+
setInfoOpen(false);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Card variant="outlined" className="indicator-card">
|
|
16
|
+
<Dialog open={infoOpen} onClose={handleInfoClose} maxWidth="xl">
|
|
17
|
+
<Typography sx={{ padding: '1rem' }} color="secondary">
|
|
18
|
+
{infoText}
|
|
19
|
+
</Typography>
|
|
20
|
+
<Button
|
|
21
|
+
onClick={handleInfoClose}
|
|
22
|
+
sx={{ alignSelf: 'end', marginRight: '0.5rem', marginBottom: '0.5rem' }}
|
|
23
|
+
>
|
|
24
|
+
Close
|
|
25
|
+
</Button>
|
|
26
|
+
</Dialog>
|
|
27
|
+
<CardContent className="card-content">
|
|
28
|
+
<Typography className="card-value" color="primary" variant="h1" component="div">
|
|
29
|
+
{valueText}
|
|
30
|
+
</Typography>
|
|
31
|
+
<Typography className="card-label">{labelText}</Typography>
|
|
32
|
+
<IconButton
|
|
33
|
+
onClick={handleInfoOpen}
|
|
34
|
+
sx={{
|
|
35
|
+
position: 'absolute',
|
|
36
|
+
right: 0,
|
|
37
|
+
top: 0,
|
|
38
|
+
color: (theme) => theme.palette.grey[500],
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
<HelpOutlineIcon />
|
|
42
|
+
</IconButton>
|
|
43
|
+
</CardContent>
|
|
44
|
+
{url && (
|
|
45
|
+
<Link
|
|
46
|
+
sx={{ color: 'text.main' }}
|
|
47
|
+
className="card-details"
|
|
48
|
+
color="secondary"
|
|
49
|
+
component="button"
|
|
50
|
+
variant="body1"
|
|
51
|
+
onClick={() => {
|
|
52
|
+
window.open(url, '_blank');
|
|
53
|
+
}}
|
|
54
|
+
>
|
|
55
|
+
{'Details'}
|
|
56
|
+
</Link>
|
|
57
|
+
)}
|
|
58
|
+
</Card>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { React } from 'react';
|
|
2
|
+
import { Box, Chip, Tooltip } from '@mui/material';
|
|
3
|
+
import ResizableGrid from '../ResizableGrid';
|
|
4
|
+
|
|
5
|
+
export function ManagementBoard({ users, mappings }) {
|
|
6
|
+
const boardMappings = mappings.filter((mp) => {
|
|
7
|
+
return mp.ManagementBoard;
|
|
8
|
+
}),
|
|
9
|
+
currentUsers = users
|
|
10
|
+
.filter((u) => {
|
|
11
|
+
return (
|
|
12
|
+
u.NFP ||
|
|
13
|
+
(u.Membership &&
|
|
14
|
+
u.Membership.some((m) => boardMappings.some((mapping) => mapping.Membership == m)))
|
|
15
|
+
);
|
|
16
|
+
})
|
|
17
|
+
.map((user) => {
|
|
18
|
+
const boardMembership =
|
|
19
|
+
user.NFP ||
|
|
20
|
+
(user.Membership &&
|
|
21
|
+
user.Membership.find((m) => boardMappings.some((mapping) => mapping.Membership == m)));
|
|
22
|
+
return {
|
|
23
|
+
id: user.id,
|
|
24
|
+
Organisation: user.Organisation,
|
|
25
|
+
Name: user.Title,
|
|
26
|
+
Email: user.Email,
|
|
27
|
+
BoardMembership: boardMembership,
|
|
28
|
+
OtherMemberships: user.OtherMemberships,
|
|
29
|
+
Membership: user.Membership,
|
|
30
|
+
};
|
|
31
|
+
}),
|
|
32
|
+
renderOtherMemberships = (params) => {
|
|
33
|
+
let index = 0,
|
|
34
|
+
allMemberships = [];
|
|
35
|
+
|
|
36
|
+
params.row.Membership && params.row.Membership.forEach((m) => allMemberships.push(m));
|
|
37
|
+
params.row.OtherMemberships &&
|
|
38
|
+
params.row.OtherMemberships.forEach((m) => allMemberships.push(m));
|
|
39
|
+
params.row.NFP && allMemberships.push(params.row.NFP);
|
|
40
|
+
|
|
41
|
+
allMemberships = allMemberships.filter((m) => m != params.row.BoardMembership);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Tooltip title={allMemberships.join(', ') || ''} arrow>
|
|
45
|
+
<div id="test">
|
|
46
|
+
{allMemberships.map((m) => (
|
|
47
|
+
<Chip variant="outlined" color="primary" key={index++} label={m} />
|
|
48
|
+
))}
|
|
49
|
+
</div>
|
|
50
|
+
</Tooltip>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const columns = [
|
|
55
|
+
{
|
|
56
|
+
field: 'Organisation',
|
|
57
|
+
headerName: 'Organisation',
|
|
58
|
+
flex: 1.5,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
field: 'BoardMembership',
|
|
62
|
+
headerName: 'Membership',
|
|
63
|
+
flex: 0.75,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
field: 'Name',
|
|
67
|
+
headerName: 'Name',
|
|
68
|
+
flex: 0.75,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
field: 'Email',
|
|
72
|
+
headerName: 'Email',
|
|
73
|
+
flex: 0.75,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
field: 'OtherMemberships',
|
|
77
|
+
headerName: 'Other Memberships',
|
|
78
|
+
flex: 0.75,
|
|
79
|
+
renderCell: renderOtherMemberships,
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
return (
|
|
83
|
+
<Box
|
|
84
|
+
sx={{
|
|
85
|
+
background: 'white',
|
|
86
|
+
height: '97%',
|
|
87
|
+
width: '100%',
|
|
88
|
+
}}
|
|
89
|
+
>
|
|
90
|
+
<ResizableGrid
|
|
91
|
+
rows={currentUsers}
|
|
92
|
+
columns={columns}
|
|
93
|
+
pageSize={25}
|
|
94
|
+
rowsPerPageOptions={[25]}
|
|
95
|
+
hideFooterSelectedRowCount={true}
|
|
96
|
+
initialState={{
|
|
97
|
+
sorting: {
|
|
98
|
+
sortModel: [
|
|
99
|
+
{
|
|
100
|
+
field: 'BoardMembership',
|
|
101
|
+
sort: 'asc',
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
}}
|
|
106
|
+
></ResizableGrid>
|
|
107
|
+
</Box>
|
|
108
|
+
);
|
|
109
|
+
}
|