DashboardCommittersAndContributors.tsx 12.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
import {
  CircularProgress,
  Container,
  createStyles,
  Grid,
  makeStyles,
  Theme,
  Typography,
  Popover,
  Link,
} from '@material-ui/core';
12
13
import PeopleAltIcon from '@material-ui/icons/PeopleAlt';
import {
14
15
16
17
  api_prefix,
  brightBlue,
  brightOrange,
  END_POINT,
18
  errMsgForGetRequest,
19
20
21
22
23
  FETCH_METHOD,
  getCurrentMode,
  iconGray,
  MODE_REACT_ONLY,
  NAV_PATHS,
24
  PERMISSIONS_BASED_ON_ROLES,
25
26
27
} from '../../../../Constants/Constants';
import CustomCard from '../../../UIComponents/CustomCard/CustomCard';
import SectionCtn from '../../../UIComponents/CustomContainer/SectionCtn';
28
import { useContext, useEffect, useState } from 'react';
29
import { fetchWrapper } from '../../../../Utils/formFunctionHelpers';
30
import { useHistory } from 'react-router';
31
import { checkPermission, pickRandomItems, renderItemList } from '../../../../Utils/portalFunctionHelpers';
32
33
34
import PortalContext from '../../../../Context/PortalContext';
import HelpIcon from '@material-ui/icons/Help';
import DashboardCommittersAndContributorsChart from './DashboardCommittersAndContributorsChart';
35

36
37
38
39
40
41
42
const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    gridCard: {
      '& > div': {
        paddingTop: theme.spacing(0.1),
        margin: 0,
        width: '100%',
43
        height: '100%',
44
45
      },
    },
46
    cbiCard: {
47
      position: 'relative',
48
      marginTop: theme.spacing(4),
49
      padding: theme.spacing(0, 1.5),
50
51
      display: 'flex',
      alignItems: 'center',
52
      minWidth: 310,
53
54
55
56
57
      minHeight: 100,
      backgroundColor: brightOrange,
      boxShadow: '1px 1px 15px rgba(0,0,0,0.1)',
      borderRadius: 4,
    },
58
    cbiIconCtn: {
59
60
61
62
63
64
65
66
67
68
69
70
71
72
      position: 'absolute',
      borderBottom: `4px solid ${brightBlue}`,
      top: theme.spacing(-2.5),
      left: theme.spacing(1.5),
      width: 54,
      height: 54,
      padding: 0,
      '& svg': {
        color: iconGray,
        width: '100%',
        height: '100%',
        paddingBottom: theme.spacing(0.5),
      },
    },
73
74
    cbiCardContent: {
      margin: theme.spacing(3, 0, 1, 0),
75
76
77
78
      display: 'flex',
      justifyContent: 'space-between',
      alignItems: 'center',
      padding: 0,
79
      width: '100%',
80
    },
81
    cbiCardSubtitle: {
82
83
84
85
86
      fontSize: 16,
    },
    cardCBIContent: {
      display: 'flex',
      flexDirection: 'column',
87
      padding: theme.spacing(0.5, 0, 0.5, 0.5),
88
89
90
91
92
93
94
95
96
97
98
    },
    cbiItem: {
      display: 'flex',
      alignItems: 'center',
    },
    bigWhiteNumber: {
      color: 'white',
      width: 38,
      marginRight: theme.spacing(1),
      textAlign: 'center',
    },
99
    boldBodyText: {
100
101
      fontWeight: 600,
    },
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
    helpButton: {
      position: 'absolute',
      right: 10,
      top: 5,
      color: 'white',
      fontSize: 25,
      cursor: 'pointer',
    },
    helpIcon: {
      fontSize: 25,
    },
    popoverText: {
      padding: theme.spacing(1.5),
    },
    customPopover: {
      '& .MuiPopover-paper': {
        boxShadow: '1px 1px 15px rgba(0,0,0,0.15)',
119
120
        width: '80vw',
        maxWidth: 600,
121
122
      },
    },
123
124
    fullWidthChartCtn: {
      width: '100%',
125
126
127
128
129
130
131
132
      height: '100%',
    },
    loadingCtn: {
      width: '100%',
      height: '100%',
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
133
134
135
    },
  })
);
136

137
const isReactOnlyMode = getCurrentMode() === MODE_REACT_ONLY;
138

139
140
export default function DashboardCommittersAndContributors() {
  const classes = useStyles();
141
142
143
144
145
  const history = useHistory();

  const [isFetchingCommitters, setIsFetchingCommitters] = useState(true);
  const [isFetchingContributors, setIsFetchingContributors] = useState(true);
  const [isFetchingCBI, setIsFetchingCBI] = useState(true);
146
  const [anchorEle, setAnchorEle] = useState<HTMLElement | null>(null);
147
148
149
150
151
152
153
154
155
156
157
  const {
    orgId,
    setContactFilterRole,
    committers,
    setCommitters,
    contributors,
    setContributors,
    cbiData,
    setCBIData,
    currentUserPortal,
  } = useContext(PortalContext);
158
  const open = Boolean(anchorEle);
159

160
161
162
  const canViewCommiters = checkPermission(PERMISSIONS_BASED_ON_ROLES.viewCommitters, currentUserPortal?.relation);
  const canViewContributors = checkPermission(PERMISSIONS_BASED_ON_ROLES.viewContributors, currentUserPortal?.relation);

163
  useEffect(() => {
164
165
166
167
    if (!canViewCommiters) {
      return;
    }

168
169
    if (!orgId || committers !== null) {
      committers !== null && setIsFetchingCommitters(false);
170
171
172
173
174
175
176
177
178
179
      return;
    }

    // For committers
    const urlForCommitters = isReactOnlyMode
      ? '/membership_data/test_committers_and_contributors.json'
      : api_prefix() + `/${END_POINT.organizations}/${orgId}/${END_POINT.committers}`;

    const saveCommittersData = (data: Array<any>) => {
      const committersData = data.map((committer) => ({
Zhou Fang's avatar
Zhou Fang committed
180
        name: `${committer.fname} ${committer.lname}`,
181
182
        url: `https://accounts.eclipse.org/users/${committer.person_id}`,
      }));
183
184
185
186
187
188
189
190
191
192
      const fiveRandomCommitters =
        committersData?.length > 0
          ? pickRandomItems(committersData, 5)
          : [
              {
                name: 'No committers yet',
                url: '',
              },
            ];

193
194
195
196
      setCommitters(fiveRandomCommitters);
      setIsFetchingCommitters(false);
    };

197
    fetchWrapper(urlForCommitters, FETCH_METHOD.GET, saveCommittersData, '', () => setIsFetchingCommitters(false));
198
  }, [orgId, committers, setCommitters, canViewCommiters]);
199
200

  useEffect(() => {
201
202
203
204
    if (!canViewContributors) {
      return;
    }

205
206
207
208
    if (!orgId || contributors !== null) {
      contributors !== null && setIsFetchingContributors(false);
      return;
    }
209
210
211
212
213
214
215
216

    // For contributors
    const urlForContributors = isReactOnlyMode
      ? '/membership_data/test_committers_and_contributors.json'
      : api_prefix() + `/${END_POINT.organizations}/${orgId}/${END_POINT.contributors}`;

    const saveContributorsData = (data: Array<any>) => {
      const contributorsData = data.map((contributors) => ({
Zhou Fang's avatar
Zhou Fang committed
217
        name: `${contributors.fname} ${contributors.lname}`,
218
219
        url: `https://accounts.eclipse.org/users/${contributors.person_id}`,
      }));
220
221
222
223
224
225
226
227
228
229
230

      const fiveRandomContributors =
        contributorsData?.length > 0
          ? pickRandomItems(contributorsData, 5)
          : [
              {
                name: 'No contributors yet',
                url: '',
              },
            ];

231
232
233
      setContributors(fiveRandomContributors);
      setIsFetchingContributors(false);
    };
234
235
236
237

    fetchWrapper(urlForContributors, FETCH_METHOD.GET, saveContributorsData, '', () =>
      setIsFetchingContributors(false)
    );
238
  }, [orgId, contributors, setContributors, canViewContributors]);
239
240
241
242
243
244

  useEffect(() => {
    if (!orgId || cbiData !== null) {
      cbiData !== null && setIsFetchingCBI(false);
      return;
    }
245
246

    // For CBI data
Zhou Fang's avatar
Zhou Fang committed
247
248
249
    const urlForCBIData = isReactOnlyMode
      ? '/membership_data/cbi_data.json'
      : 'https://api.eclipse.org/cbi/sponsorships';
250
251

    const saveCBIData = (data: { memberOrganizationsBenefits: Array<any>; sponsoredProjects: Array<any> }) => {
252
      const allocated = data.memberOrganizationsBenefits.find((item) => item.id === orgId)?.resourcePacks || 0;
253
254
255
256
257
258
259
260
261
      let inUse = 0;
      data.sponsoredProjects.forEach((item) => {
        item.sponsoringOrganizations.forEach((org: any) => {
          org.id === orgId && inUse++;
        });
      });
      setCBIData({ inUse, allocated });
      setIsFetchingCBI(false);
    };
262
263

    fetchWrapper(urlForCBIData, FETCH_METHOD.GET, saveCBIData, '', () => setIsFetchingCBI(false));
264
  }, [orgId, cbiData, setCBIData]);
265

266
267
268
  return (
    <SectionCtn title="Committers and Contributors" id="committers-contributors">
      <Grid container spacing={4}>
269
        <Grid item container xs>
270
271
272
273
274
275
276
277
278
          {canViewContributors && canViewCommiters && (
            <Grid item container spacing={4}>
              {canViewCommiters && (
                <Grid item xs className={classes.gridCard}>
                  <CustomCard
                    isFetching={isFetchingCommitters}
                    subtitle="Your Committers"
                    color={brightBlue}
                    icon={<PeopleAltIcon />}
279
                    listItems={renderItemList(committers, isFetchingCommitters, 'No committers yet', '')}
280
                    urlText="View All"
281
282
283
284
285
286
287
288
289
290
291
292
293
294
                    callBackFunc={() => {
                      setContactFilterRole('committer');
                      history.push(NAV_PATHS.contactManagement);
                    }}
                  />
                </Grid>
              )}
              {canViewContributors && (
                <Grid item xs className={classes.gridCard}>
                  <CustomCard
                    isFetching={isFetchingContributors}
                    subtitle="Your Contributors"
                    color={brightBlue}
                    icon={<PeopleAltIcon />}
295
                    listItems={renderItemList(contributors, isFetchingContributors, 'No contributors yet', '')}
296
                    urlText="View All"
297
                    callBackFunc={() => {
298
                      setContactFilterRole('contributor');
299
300
301
302
303
                      history.push(NAV_PATHS.contactManagement);
                    }}
                  />
                </Grid>
              )}
304
            </Grid>
305
306
          )}

307
          <Grid item xs>
308
309
            <Container className={classes.cbiCard}>
              <Container className={classes.cbiIconCtn}>
310
311
                <PeopleAltIcon />
              </Container>
312
313
              <Container className={classes.cbiCardContent}>
                <Typography variant="h6" component="h3" className={classes.cbiCardSubtitle}>
314
315
316
                  Common Build Infrastructure
                </Typography>
                <Container className={classes.cardCBIContent}>
317
318
319
320
                  {isFetchingCBI ? (
                    <div className={classes.loadingCtn}>
                      <CircularProgress color="secondary" />
                    </div>
321
                  ) : cbiData ? (
322
323
324
325
326
                    <>
                      <div className={classes.cbiItem}>
                        <Typography variant="h4" className={classes.bigWhiteNumber}>
                          {cbiData?.inUse}
                        </Typography>
327
                        <Typography variant="body1" className={classes.boldBodyText}>
328
329
330
331
332
333
334
                          resource packs in use
                        </Typography>
                      </div>
                      <div className={classes.cbiItem}>
                        <Typography variant="h4" className={classes.bigWhiteNumber}>
                          {cbiData?.allocated}
                        </Typography>
335
                        <Typography variant="body1" className={classes.boldBodyText}>
336
337
338
339
                          resource packs allocated
                        </Typography>
                      </div>
                    </>
340
341
342
343
344
                  ) : (
                    // If the isFetching is false and CBI data is still null, that means GET request fails, show err msg.
                    <Typography variant="body1" className={classes.boldBodyText}>
                      {errMsgForGetRequest}
                    </Typography>
345
                  )}
346
                  <div className={classes.helpButton} onClick={(ev) => setAnchorEle(ev.currentTarget)}>
347
348
349
350
351
352
353
354
                    <HelpIcon className={classes.helpIcon} />
                  </div>
                  <Popover
                    id={open ? 'simple-popover' : undefined}
                    className={classes.customPopover}
                    elevation={4}
                    open={open}
                    anchorEl={anchorEle}
355
                    onClose={() => setAnchorEle(null)}
356
357
358
359
360
361
362
363
364
365
                    anchorOrigin={{
                      vertical: -65,
                      horizontal: 'center',
                    }}
                    transformOrigin={{
                      vertical: 'top',
                      horizontal: 'center',
                    }}
                  >
                    <Typography variant="body1" className={classes.popoverText}>
366
367
                      Eclipse Foundation offers a Common Build environment for all its Open Source projects. Member
                      Organizations have access to additional{' '}
368
369
370
371
372
373
374
                      <Link
                        href="https://wiki.eclipse.org/CBI#Resource_Packs_Included_in_Membership"
                        target="_blank"
                        rel="noopener"
                      >
                        Resource Packs based on their membership level
                      </Link>
375
376
377
378
                      . For more information about build resources, please refer to{' '}
                      <Link href="https://wiki.eclipse.org/CBI" target="_blank" rel="noopener">
                        CBI Wiki
                      </Link>
379
380
381
                      .
                    </Typography>
                  </Popover>
382
383
384
385
386
                </Container>
              </Container>
            </Container>
          </Grid>
        </Grid>
387
        <Grid item xs lg={6}>
388
          <DashboardCommittersAndContributorsChart />
389
390
391
        </Grid>
      </Grid>
    </SectionCtn>
392
393
  );
}