UniversityOffers.jsx 5.43 KB
Newer Older
1
/* eslint-disable indent */
2
import React, { useEffect, useState } from "react";
3
4
5
6
7
import PropTypes from "prop-types";
import compose from "recompose/compose";
import Close from "@material-ui/icons/Close";
import DoneAll from "@material-ui/icons/DoneAll";
import Paper from "@material-ui/core/Paper";
8
import { makeStyles } from "@material-ui/styles";
9
10
import Typography from "@material-ui/core/Typography";
import Chip from "@material-ui/core/Chip";
Florent Chehab's avatar
Florent Chehab committed
11
import withUnivInfo from "../../../hoc/withUnivInfo";
12
import RequestParams from "../../../redux/api/RequestParams";
13
import PaginatedData from "../../common/PaginatedData";
14
15
16
17
import withNetworkWrapper, {
  getApiPropTypes,
  NetWrapParam
} from "../../../hoc/withNetworkWrapper";
18

19
const useStyles = makeStyles(theme => ({
20
  paper: {
21
    padding: theme.spacing(1)
22
23
24
25
26
27
28
  },
  chip: {
    margin: theme.spacing(0.5)
  },
  inlineIcon: {
    fontSize: "1em",
    position: "relative",
29
    top: ".125em"
30
31
32
  },
  itemRoot: {
    marginTop: theme.spacing(1),
33
    marginBottom: theme.spacing(1)
34
  }
35
}));
36
37

function Item(props) {
38
  const { majors, semester, seats, comment, master, doubleDegree } = props;
39
  const classes = useStyles();
40
41
42
43

  return (
    <div className={classes.itemRoot}>
      <div>
44
45
46
47
48
49
50
51
52
        <Chip label={semester} color="primary" className={classes.chip} />
        {majors.map(spe => (
          <Chip
            key={spe}
            label={<b>{spe}</b>}
            className={classes.chip}
            color="secondary"
          />
        ))}
53
54
      </div>
      <div>
55
56
57
58
59
60
61
        {seats ? (
          <>
            <Typography display="inline">Au total,&nbsp;</Typography>
            <Typography color="primary" display="inline">
              {seats}
              &nbsp; place
              {seats > 1 ? "s" : ""}
62
            </Typography>
63
64
65
66
67
68
69
70
71
72
73
            <Typography display="inline">
              &nbsp;
              {seats > 1 ? "étaient/sont disponibles" : "est/disponible"}.
            </Typography>
          </>
        ) : (
          <Typography variant="caption">
            Aucune information n'est disponible concernant le nombre de places
            disponibles.
          </Typography>
        )}
74
75
        <div>
          <Typography>
76
            Master&nbsp;
77
78
79
80
81
            {master ? (
              <DoneAll className={classes.inlineIcon} color="primary" />
            ) : (
              <Close className={classes.inlineIcon} color="error" />
            )}
82
83
          </Typography>
          <Typography>
84
            Double diplome&nbsp;
85
86
87
88
89
            {doubleDegree ? (
              <DoneAll className={classes.inlineIcon} color="primary" />
            ) : (
              <Close className={classes.inlineIcon} color="error" />
            )}
90
91
92
          </Typography>
        </div>
        <div>
93
          {comment && (
94
            <>
95
              <Typography variant="caption">Commentaire de la DRI :</Typography>
96
97
98
99
100
              <Typography>
                <em>{comment}</em>
              </Typography>
            </>
          )}
101
102
103
104
105
106
107
108
109
110
        </div>
      </div>
    </div>
  );
}

Item.propTypes = {
  doubleDegree: PropTypes.bool.isRequired,
  master: PropTypes.bool.isRequired,
  semester: PropTypes.string.isRequired,
Florent Chehab's avatar
Florent Chehab committed
111
  majors: PropTypes.arrayOf(PropTypes.string).isRequired,
112
  comment: PropTypes.string,
113
  seats: PropTypes.number
114
115
};

116
117
118
119
120
Item.defaultProps = {
  comment: "",
  seats: null
};

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
function renderEl(dataEl) {
  const {
    comment,
    double_degree: doubleDegree,
    is_master_offered: master,
    semester,
    year,
    majors,
    id,
    nb_seats_offered: seats
  } = dataEl;

  const p = {
    seats,
    id,
    doubleDegree,
    comment,
    master,
    majors: typeof majors === "string" ? majors.split(",") : [],
    semester: `${semester}${year}`
141
142
  };

143
144
  return <Item key={p.id} {...p} />;
}
145

146
147
148
149
150
const buildParams = (univId, page) =>
  RequestParams.Builder.withQueryParam("university", univId)
    .withQueryParam("page", page)
    .withQueryParam("page_size", 1)
    .build();
151

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
function UniversityOffers({ offers, api, univId, page, goToPage }) {
  const classes = useStyles();

  useEffect(() => {
    api.offers.setParams(buildParams(univId, page));
  }, [univId, page]);

  return (
    <Paper className={classes.paper}>
      <Typography variant="h4">Possibilité(s) d'échanges</Typography>
      <Typography variant="caption">
        REX-DRI s'efforce d'être à jour avec l'ENT. Toutefois, seul l'ENT fait
        foi à 100% concernant les possibilités passées et actuelles d'échanges.
      </Typography>

      <PaginatedData
        data={offers}
        goToPage={goToPage}
        render={renderEl}
        stepperOnBottom
        stepperOnTop={false}
        EmptyMessageComponent={
          <Typography>
            <em>
              Aucune possibilité (passée ou présente) n'a été enregistrée à ce
              jour.
            </em>
          </Typography>
        }
      />
    </Paper>
  );
184
185
186
}

UniversityOffers.propTypes = {
187
  univId: PropTypes.number.isRequired,
188
189
190
191
  offers: PropTypes.object.isRequired,
  api: getApiPropTypes("offers").isRequired,
  page: PropTypes.number.isRequired,
  goToPage: PropTypes.func.isRequired
192
193
};

194
const ConnectedComponent = compose(
195
  withUnivInfo(),
196
197
198
199
200
  withNetworkWrapper([
    new NetWrapParam("offers", "all", "offers", props =>
      buildParams(props.univId, props.page)
    )
  ])
201
)(UniversityOffers);
202
203
204
205
206
207
208

export default () => {
  // Lifting state up to work around NetworkWrapper limitations
  const [page, goToPage] = useState(1);

  return <ConnectedComponent page={page} goToPage={goToPage} />;
};