Commit d3681935 authored by Florent Chehab's avatar Florent Chehab

refactor(smart actions parameters) : BREAKING & tweaks

* Created `RequestedParams` class with builder to create request parameters object in a standard way,
* All the generic actions only take an instance of this object now,
* All dynamic parametrization of the request params now happens in `apiParams`
* This enables an ultra smart magic piece of logic to auto refresh the data from the server if the props / state of the component has changed since the last request. (the requestParams object are now stored in the redux store and we can compare theme 😄 ). And also not to make duplicate queries.
* Updated doc accordingly,

Tweaks/fixes:
* use of `lodash/isEqual` to deep compare objects
* Removed now useless behiavor
parent 6b4719a2
Pipeline #38664 passed with stages
in 3 minutes and 16 seconds
...@@ -222,23 +222,24 @@ const mapDispatchToProps = (dispatch) => { ...@@ -222,23 +222,24 @@ const mapDispatchToProps = (dispatch) => {
The `getActions` function will give you access to all of the following functions (which are defined in the `CrudActions` class -- `frontend/src/redux/api/CrudActions.js`): The `getActions` function will give you access to all of the following functions (which are defined in the `CrudActions` class -- `frontend/src/redux/api/CrudActions.js`):
- `readAll(params={})` - `readAll(params=RequestParams.Builder.build())`
- `readOne(id, params={})` - `readOne(params)`
- `create(data, onSuccessCallback = (newData) => { }, params = {})` - `create(params)`
- `update(id, data, onSuccessCallback = (newData) => { }, params = {})` - `update(params)`
- `delete(id, onSuccessCallback = () => { }, params = {})` - `delete(params)`
?> `params` **must be an instance of `RequestParams`**, which is a helper class defined in the project. This class comes with a handy `Builder` static class (say hello to the Builder design pattern) to help you parameterize your requests. Here is a quick summary of the functions provided by the builder (all are *optional*):
?> `params` is an object that accepts two keys: `queryParams` and `endPointAttr`. In most cases it should be created through the `getQueryParams` and `getEndPointAttr` (and `mapDispatchToProps`; see just before [this section](Application/Frontend/redux?id=words-on-updating-data-on-the-api)) functions of your components. * `withId(id)`: specify the id that will be added to the url (eg: `withId(1)` => `/endpoint/1`)
* `withData(data)`: specify the payload that will go with request (useful for creating/updating models instances)
* `withQueryParam(key, value)`: add a *query param* to the request object (eg: `withQueryParam("currency", "CHF")` will result in the request `/endpoint?currency=CHF`); you can chain multiple `withQueryParam`.
* `withEndPointAttrs(endPointAttrs)`: `endPointAttrs` should be an array of the endpoint attributes to add to the endpoint (`withEndPointAttrs([10, 11])` will render as `/endpoint/10/11/`).
* ` withOnSuccessCallback(callback)`: register a callback that will be called when the request is successful. *The data returned by the server will be passed as parameter to this callback.*
* `build()`: to conclude the building process :smile:
> * `queryParams` should be an object that maps the fields to the values you want to filter on (`queryParams = {university: 1, country: 2}` will render as `/api/endpoint?university=1&country=2`). ?> :information_desk_person: All those functions can be chained.
> * `endPointAttr` should be an array of the endpoint attributes to add to the endpoint (`endPointAttr = [10, 11]` will render as `/api/endpoint/10/11/`)
?> `id` should be the id of the object your want to read, update or delete. !> Never forget the `.build()` at the end of your chain.
?> `data` would be the expected content of the model instance
?> `onSuccessCallback` is a callback called if the action is successful. The returned data from the API is given to it as a parameter. **It is useful to ease some interactions inside your components: you can boycott redux in some way.**
You also have actions to clear the failures if you need: You also have actions to clear the failures if you need:
...@@ -257,7 +258,7 @@ And actions related to invalidating the data: ...@@ -257,7 +258,7 @@ And actions related to invalidating the data:
!> Not all actions might be performed on any given endpoint: your request my get rejected by the backend depending on the viewset's `permission_classes`, the object, the user who sent the request, etc. !> Not all actions might be performed on any given endpoint: your request my get rejected by the backend depending on the viewset's `permission_classes`, the object, the user who sent the request, etc.
?> :information_desk_person: invalidating data will usually trigger a refresh of that data with a new API call. This behavior is implementer in `CustomComponentForApi` ?> :information_desk_person: invalidating data will usually trigger a refresh of that data with a new API call. This behavior is implemented in `CustomComponentForApi`
?> Do you recall that an update to the redux store will be propagated to the components that imported that portion of the store (concerned by the update). So they will be updated on their own every time new data comes in, like magic! :confetti_ball: ?> Do you recall that an update to the redux store will be propagated to the components that imported that portion of the store (concerned by the update). So they will be updated on their own every time new data comes in, like magic! :confetti_ball:
...@@ -305,9 +306,36 @@ const mapDispatchToProps = (dispatch) => { ...@@ -305,9 +306,36 @@ const mapDispatchToProps = (dispatch) => {
!> **The function that will be used to dispatch the action associated with fetching the data for `propName` must be identified by `api.propName` in the `mapDispatchToProps` function.** !> **The function that will be used to dispatch the action associated with fetching the data for `propName` must be identified by `api.propName` in the `mapDispatchToProps` function.**
<div id="customGettersApi"></div> #### Dynamic parametrization of the requests
Often, you will need to access data on the API based on a value stored in the `props` of your components. As a result you need to generate a new `RequestParams` object on demand.
:warning: To do so, in your component you should define he **`apiParams`** property like follow:
```js
apiParams = {
countryDri: ({props, state}) => RequestParams.Builder.withQueryParam("countries", props.countryId).build()
};
```
`apiParams` is an object with keys the `propName` (we have been talking about before) and value a function that accepts an object and that **must return** a `RequestParams` instance.
Then, automatically and when needed, a new `RequestParams` will be built by the internal functions of `CustomComponentForApi`; as you can see this *mapper* function takes as an argument an object with two keys that corresponds to the current `state` and `props` of the object.
When using `apiParams`, your `mapDispatchToProps` should look like this:
```js
const mapDispatchToProps = (dispatch) => {
return {
api: {
countryDri: (params) => dispatch(getActions("countryDri").readAll(params)),
},
};
};
```
Your function must take one argument (`params`) (that will be automatically built) and pass it down to the action like a breeze.
?> :information_desk_person: All the subfunctions you define in `mapDispatchToProps` under the `api` key will be given one object parameter you may want to use. It is composed as follow: `{props, params}`. `props` will be an object corresponding to the `props` of the *connected* component. `params` is built with the `getQueryParams` and `getEndPointAttr` you may wish to override in your connected components. **`params` shall be *passed on* for filtering to work correctly**. ?> :information_desk_person: For all "dynamic" attributes (defined inside `apiParams`) some awesome magical behaviors will be automatically inherited, such as the fact that a new request will be made to the server if the parametrization has changed (e.g. if a `prop` has changed) without needing to detect it yourself (only on ). :tada: This behavior is only present on `ComponentDidMount` react hook. If you want to activate it on `ComponentDidUpdate`, you should set `enableSmartDataRefreshOnComponentDidUpdate = true` as a component property.
That's all :confetti_ball:. That's all :confetti_ball:.
......
...@@ -9,6 +9,7 @@ import CustomComponentForAPI from "./CustomComponentForAPI"; ...@@ -9,6 +9,7 @@ import CustomComponentForAPI from "./CustomComponentForAPI";
import "typeface-roboto"; import "typeface-roboto";
import getActions from "../../redux/api/getActions"; import getActions from "../../redux/api/getActions";
import {RequestParams} from "../../redux/api/RequestParams";
const siteSettings = { const siteSettings = {
typography: { typography: {
...@@ -76,7 +77,7 @@ const mapDispatchToProps = (dispatch) => { ...@@ -76,7 +77,7 @@ const mapDispatchToProps = (dispatch) => {
api: { api: {
// __AppUserId is defined in the html rendered by django // __AppUserId is defined in the html rendered by django
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
userData: () => dispatch(getActions("userData").readOne(__AppUserId)), userData: () => dispatch(getActions("userData").readOne(RequestParams.Builder.withId(__AppUserId).build())),
}, },
}; };
}; };
......
import getActions from "../../redux/api/getActions"; import getActions from "../../redux/api/getActions";
import { openFullScreenDialog, closeFullScreenDialog } from "../../redux/actions/fullScreenDialog"; import { openFullScreenDialog, closeFullScreenDialog } from "../../redux/actions/fullScreenDialog";
import {RequestParams} from "../../redux/api/RequestParams";
/** /**
* Function to create the mapDispatchToProps function for editor in a "generic way" * Function to create the mapDispatchToProps function for editor in a "generic way"
...@@ -13,13 +14,22 @@ export default function getMapDispatchToPropsForEditor(name) { ...@@ -13,13 +14,22 @@ export default function getMapDispatchToPropsForEditor(name) {
let lastSave = "update"; let lastSave = "update";
return { return {
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
saveData: (data, onSuccessCallback = (newData) => { }) => { saveData: (data, onSuccessCallback = new Function()) => {
if ("id" in data) { // it's an update if ("id" in data) { // it's an update
lastSave = "update"; lastSave = "update";
dispatch(getActions(name).update(data.id, data, onSuccessCallback)); const params = RequestParams.Builder
.withId(data.id)
.withData(data)
.withOnSuccessCallback(onSuccessCallback)
.build();
dispatch(getActions(name).update(params));
} else { // it's a create } else { // it's a create
lastSave = "create"; lastSave = "create";
dispatch(getActions(name).create(data, onSuccessCallback)); const params = RequestParams.Builder
.withData(data)
.withOnSuccessCallback(onSuccessCallback)
.build();
dispatch(getActions(name).create(params));
} }
}, },
openFullScreenDialog: (innerNodes) => dispatch(openFullScreenDialog(innerNodes)), openFullScreenDialog: (innerNodes) => dispatch(openFullScreenDialog(innerNodes)),
......
import {Component} from "react"; import {Component} from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import areSameObjects from "../../utils/areSameObjects"; import isEqual from "lodash/isEqual";
import renderFieldsMixIn from "./renderFieldsMixIn"; import renderFieldsMixIn from "./renderFieldsMixIn";
import CustomError from "../common/CustomError"; import CustomError from "../common/CustomError";
...@@ -58,7 +58,8 @@ class Form extends Component { ...@@ -58,7 +58,8 @@ class Form extends Component {
* with resetting it for some reason * with resetting it for some reason
* @type {object.<string, Field>} * @type {object.<string, Field>}
*/ */
fields = Object(); fields = {};
/** /**
* Array containing the possible form level errors * Array containing the possible form level errors
* @abstract * @abstract
...@@ -142,7 +143,7 @@ class Form extends Component { ...@@ -142,7 +143,7 @@ class Form extends Component {
// we need to compare objects (ie JSON objects) differently // we need to compare objects (ie JSON objects) differently
if (typeof cmp1 === "object") { if (typeof cmp1 === "object") {
return !areSameObjects(cmp1, cmp2); return !isEqual(cmp1, cmp2);
} else { } else {
return cmp1 !== cmp2; return cmp1 !== cmp2;
} }
......
...@@ -22,7 +22,7 @@ class MultiSelectField extends Field { ...@@ -22,7 +22,7 @@ class MultiSelectField extends Field {
constructor(props) { constructor(props) {
super(props); super(props);
this.optionsByValue = Object(); this.optionsByValue = {};
props.options.map((opt) => this.optionsByValue[opt.value] = opt.label); props.options.map((opt) => this.optionsByValue[opt.value] = opt.label);
} }
......
...@@ -16,7 +16,6 @@ import {Redirect} from "react-router-dom"; ...@@ -16,7 +16,6 @@ import {Redirect} from "react-router-dom";
import getActions from "../../redux/api/getActions"; import getActions from "../../redux/api/getActions";
import {saveUniversityBeingViewed} from "../../redux/actions/universityPage";
import compose from "recompose/compose"; import compose from "recompose/compose";
import {withStyles} from "@material-ui/core"; import {withStyles} from "@material-ui/core";
import {withErrorBoundary} from "../common/ErrorBoundary"; import {withErrorBoundary} from "../common/ErrorBoundary";
...@@ -24,6 +23,7 @@ import {APP_ROUTES} from "../../config/appRoutes"; ...@@ -24,6 +23,7 @@ import {APP_ROUTES} from "../../config/appRoutes";
import CustomNavLink from "../common/CustomNavLink"; import CustomNavLink from "../common/CustomNavLink";
import CustomLink from "../common/CustomLink"; import CustomLink from "../common/CustomLink";
let previousUnivId = -1;
/** /**
* Component holding the page with the university details * Component holding the page with the university details
...@@ -34,23 +34,22 @@ import CustomLink from "../common/CustomLink"; ...@@ -34,23 +34,22 @@ import CustomLink from "../common/CustomLink";
*/ */
class PageUniversity extends CustomComponentForAPI { class PageUniversity extends CustomComponentForAPI {
componentDidUpdate(prevProps, prevState, snapshot) { componentDidMount() {
super.componentDidUpdate(prevProps, prevState, snapshot); super.componentDidMount();
const requestedUnivId = this.getUnivIdFromProps();
if (this.props.universities.readSucceeded.readAt) { if (requestedUnivId && requestedUnivId !== "previousOne") {
// we have the university data previousUnivId = requestedUnivId;
const universities = this.getLatestReadData("universities"),
{match, universityBeingViewed} = this.props,
requestedUniversity = match.params.univId;
if (requestedUniversity != "undefined"
&& universities.find(univ => univ.id == requestedUniversity)
&& requestedUniversity != universityBeingViewed) {
this.props.saveUniversityInView(requestedUniversity);
} }
} }
componentDidUpdate(prevProps, prevState, snapshot) {
super.componentDidUpdate(prevProps, prevState, snapshot);
} }
getUnivIdFromProps() {
return this.props.match.params.univId;
}
renderUniversityNotFound() { renderUniversityNotFound() {
return ( return (
...@@ -82,7 +81,8 @@ class PageUniversity extends CustomComponentForAPI { ...@@ -82,7 +81,8 @@ class PageUniversity extends CustomComponentForAPI {
return ( return (
<Paper className={this.props.classes.paper}> <Paper className={this.props.classes.paper}>
<Typography> <Typography>
C'est la première fois que vous consulter cet onglet. Nous vous invitons à <CustomLink to={APP_ROUTES.map}>parcourir les universités</CustomLink> dans un C'est la première fois que vous consulter cet onglet. Nous vous invitons à <CustomLink to={APP_ROUTES.map}>parcourir
les universités</CustomLink> dans un
premier temps. 😁 premier temps. 😁
</Typography> </Typography>
</Paper> </Paper>
...@@ -99,14 +99,14 @@ class PageUniversity extends CustomComponentForAPI { ...@@ -99,14 +99,14 @@ class PageUniversity extends CustomComponentForAPI {
} }
customRender() { customRender() {
const {match, universityBeingViewed} = this.props, const {match} = this.props,
requestedUnivId = match.params.univId, requestedUnivId = match.params.univId,
tabName = match.params.tabName, tabName = match.params.tabName,
universities = this.getLatestReadData("universities"); universities = this.getLatestReadData("universities");
if (requestedUnivId === "previousOne" || typeof requestedUnivId === "undefined") { if (requestedUnivId === "previousOne" || typeof requestedUnivId === "undefined") {
if (universityBeingViewed != null) { if (previousUnivId !== -1) {
return this.renderUniversityUndefinedButHavePrevious(universityBeingViewed); return this.renderUniversityUndefinedButHavePrevious(previousUnivId);
} else { } else {
return this.renderFirstTimeHere(); return this.renderFirstTimeHere();
} }
...@@ -121,17 +121,14 @@ class PageUniversity extends CustomComponentForAPI { ...@@ -121,17 +121,14 @@ class PageUniversity extends CustomComponentForAPI {
} }
PageUniversity.propTypes = { PageUniversity.propTypes = {
universityBeingViewed: PropTypes.string,
universities: PropTypes.object.isRequired, universities: PropTypes.object.isRequired,
match: PropTypes.object.isRequired, match: PropTypes.object.isRequired,
saveUniversityInView: PropTypes.func.isRequired,
classes: PropTypes.object.isRequired, classes: PropTypes.object.isRequired,
}; };
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return { return {
universities: state.api.universitiesAll, universities: state.api.universitiesAll,
universityBeingViewed: state.app.universityBeingViewed
}; };
}; };
...@@ -140,7 +137,6 @@ const mapDispatchToProps = (dispatch) => { ...@@ -140,7 +137,6 @@ const mapDispatchToProps = (dispatch) => {
api: { api: {
universities: () => dispatch(getActions("universities").readAll()), universities: () => dispatch(getActions("universities").readAll()),
}, },
saveUniversityInView: (univId) => dispatch(saveUniversityBeingViewed(univId))
}; };
}; };
......
...@@ -26,11 +26,12 @@ import ExpansionPanel from "@material-ui/core/ExpansionPanel/index"; ...@@ -26,11 +26,12 @@ import ExpansionPanel from "@material-ui/core/ExpansionPanel/index";
import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary/index"; import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary/index";
import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails/index"; import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails/index";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore"; import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import areSameObjects from "../../../utils/areSameObjects"; import isEqual from "lodash/isEqual";
import defaultSiteTheme from "../../../config/defaultTheme.json"; import defaultSiteTheme from "../../../config/defaultTheme.json";
import Divider from "@material-ui/core/Divider/index"; import Divider from "@material-ui/core/Divider/index";
import TextLink from "../../common/TextLink"; import TextLink from "../../common/TextLink";
import {deepCopy} from "../../../utils/deepCopy"; import {deepCopy} from "../../../utils/deepCopy";
import {RequestParams} from "../../../redux/api/RequestParams";
const isRgb = string => /#?([0-9a-f]{6})/i.test(string); const isRgb = string => /#?([0-9a-f]{6})/i.test(string);
...@@ -254,7 +255,7 @@ class ColorTool extends CustomComponentForAPI { ...@@ -254,7 +255,7 @@ class ColorTool extends CustomComponentForAPI {
customRender() { customRender() {
const {classes} = this.props, const {classes} = this.props,
themeForDemo = getTheme(this.state.theme), themeForDemo = getTheme(this.state.theme),
hasChanges = !areSameObjects(this.state.theme, this.getInitialTheme()), hasChanges = !isEqual(this.state.theme, this.getInitialTheme()),
darkModeActivated = this.state.theme.mode === "dark"; darkModeActivated = this.state.theme.mode === "dark";
return ( return (
...@@ -310,11 +311,11 @@ const mapStateToProps = (state) => { ...@@ -310,11 +311,11 @@ const mapStateToProps = (state) => {
const mapDispatchToProps = (dispatch) => { const mapDispatchToProps = (dispatch) => {
return { return {
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
saveUserDataToServer: (data) => dispatch(getActions("userData").update(__AppUserId, data)), saveUserDataToServer: (data) => dispatch(getActions("userData").update(RequestParams.Builder.withId(__AppUserId).withData(data).build())),
api: { api: {
// __AppUserId is defined in the html rendered by django // __AppUserId is defined in the html rendered by django
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
userData: () => dispatch(getActions("userData").readOne(__AppUserId)), // id not needed userData userData: () => dispatch(getActions("userData").readOne(RequestParams.Builder.withId(__AppUserId).build())), // id not needed userData
}, },
}; };
}; };
......
...@@ -14,6 +14,7 @@ import ModuleGroupWrapper from "./common/ModuleGroupWrapper"; ...@@ -14,6 +14,7 @@ import ModuleGroupWrapper from "./common/ModuleGroupWrapper";
import CountryDriEditor from "../editors/CountryDriEditor"; import CountryDriEditor from "../editors/CountryDriEditor";
import getActions from "../../../redux/api/getActions"; import getActions from "../../../redux/api/getActions";
import {withUnivInfo} from "../common/withUnivInfo"; import {withUnivInfo} from "../common/withUnivInfo";
import {RequestParams} from "../../../redux/api/RequestParams";
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
...@@ -29,10 +30,9 @@ function renderCore(rawModelData, classes, outsideData) { ...@@ -29,10 +30,9 @@ function renderCore(rawModelData, classes, outsideData) {
} }
class CountryDri extends Module { class CountryDri extends Module {
/** apiParams = {
* @override countryDri: ({props}) => RequestParams.Builder.withQueryParam("countries", props.countryId).build(),
*/ };
getQueryParams = (propName) => propName === "countryDri" ? ({ countries: this.props.countryId }) : undefined;
customRender() { customRender() {
const countryDriItems = this.getOnlyReadData("countryDri"), const countryDriItems = this.getOnlyReadData("countryDri"),
...@@ -86,7 +86,7 @@ const mapStateToProps = (state) => { ...@@ -86,7 +86,7 @@ const mapStateToProps = (state) => {
const mapDispatchToProps = (dispatch) => { const mapDispatchToProps = (dispatch) => {
return { return {
api: { api: {
countryDri: ({ params }) => dispatch(getActions("countryDri").readAll(params)), countryDri: (params) => dispatch(getActions("countryDri").readAll(params)),
}, },
invalidateData: () => dispatch(getActions("countryDri").invalidateAll()) invalidateData: () => dispatch(getActions("countryDri").invalidateAll())
}; };
......
...@@ -16,6 +16,7 @@ import CountryScholarshipEditor from "../editors/CountryScholarshipEditor"; ...@@ -16,6 +16,7 @@ import CountryScholarshipEditor from "../editors/CountryScholarshipEditor";
import getActions from "../../../redux/api/getActions"; import getActions from "../../../redux/api/getActions";
import {withUnivInfo} from "../common/withUnivInfo"; import {withUnivInfo} from "../common/withUnivInfo";
import {RequestParams} from "../../../redux/api/RequestParams";
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
...@@ -43,11 +44,9 @@ function renderCore(rawModelData, classes, outsideData) { ...@@ -43,11 +44,9 @@ function renderCore(rawModelData, classes, outsideData) {
class CountryScholarships extends Module { class CountryScholarships extends Module {
apiParams = {
/** countryScholarships: ({props}) => RequestParams.Builder.withQueryParam("countries", props.countryId).build(),
* @override };
*/
getQueryParams = (propName) => propName === "countryScholarships" ? ({countries: this.props.countryId}) : undefined;
customRender() { customRender() {
const countryScholarshipsItems = this.getOnlyReadData("countryScholarships"), const countryScholarshipsItems = this.getOnlyReadData("countryScholarships"),
...@@ -111,7 +110,7 @@ const mapStateToProps = (state) => { ...@@ -111,7 +110,7 @@ const mapStateToProps = (state) => {
const mapDispatchToProps = (dispatch) => { const mapDispatchToProps = (dispatch) => {
return { return {
api: { api: {
countryScholarships: ({params}) => dispatch(getActions("countryScholarships").readAll(params)), countryScholarships: (params) => dispatch(getActions("countryScholarships").readAll(params)),
}, },
invalidateData: () => dispatch(getActions("countryScholarships").invalidateAll()) invalidateData: () => dispatch(getActions("countryScholarships").invalidateAll())
}; };
......
...@@ -2,7 +2,7 @@ import React from "react"; ...@@ -2,7 +2,7 @@ import React from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import withStyles from "@material-ui/core/styles/withStyles"; import withStyles from "@material-ui/core/styles/withStyles";
import compose from "recompose/compose"; import compose from "recompose/compose";
import { connect } from "react-redux"; import {connect} from "react-redux";
import Markdown from "../../common/Markdown"; import Markdown from "../../common/Markdown";
...@@ -15,6 +15,7 @@ import UniversityDriEditor from "../editors/UniversityDriEditor"; ...@@ -15,6 +15,7 @@ import UniversityDriEditor from "../editors/UniversityDriEditor";
import getActions from "../../../redux/api/getActions"; import getActions from "../../../redux/api/getActions";
import {withUnivInfo} from "../common/withUnivInfo"; import {withUnivInfo} from "../common/withUnivInfo";
import {RequestParams} from "../../../redux/api/RequestParams";
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const styles = theme => ({ const styles = theme => ({
...@@ -22,8 +23,7 @@ const styles = theme => ({ ...@@ -22,8 +23,7 @@ const styles = theme => ({
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
function renderCore(rawModelData, classes, outsideData) { function renderCore(rawModelData, classes, outsideData) {
const univDri = rawModelData; const { comment } = rawModelData;
const { comment } = univDri;
return ( return (
<Markdown source={comment} /> <Markdown source={comment} />
...@@ -32,11 +32,9 @@ function renderCore(rawModelData, classes, outsideData) { ...@@ -32,11 +32,9 @@ function renderCore(rawModelData, classes, outsideData) {
class UniversityDri extends Module { class UniversityDri extends Module {
apiParams = {
/** universityDri: ({props}) => RequestParams.Builder.withQueryParam("universities", props.univId).build(),
* @override };
*/
getQueryParams = (propName) => propName === "universityDri" ? ({ universities: this.props.univId }) : undefined;
customRender() { customRender() {
const { universities, classes } = this.props, const { universities, classes } = this.props,
...@@ -90,7 +88,7 @@ const mapStateToProps = (state) => { ...@@ -90,7 +88,7 @@ const mapStateToProps = (state) => {
const mapDispatchToProps = (dispatch) => { const mapDispatchToProps = (dispatch) => {
return { return {
api: { api: {
universityDri: ({ params }) => dispatch(getActions("universityDri").readAll(params)), universityDri: (params) => dispatch(getActions("universityDri").readAll(params)),
}, },
invalidateData: () => dispatch(getActions("universityDri").invalidateAll()) invalidateData: () => dispatch(getActions("universityDri").invalidateAll())
}; };
......
...@@ -18,6 +18,7 @@ import UniversityGeneralEditor from "../editors/UniversityGeneralEditor"; ...@@ -18,6 +18,7 @@ import UniversityGeneralEditor from "../editors/UniversityGeneralEditor";
import getActions from "../../../redux/api/getActions"; import getActions from "../../../redux/api/getActions";
import {withUnivInfo} from "../common/withUnivInfo"; import {withUnivInfo} from "../common/withUnivInfo";
import {RequestParams} from "../../../redux/api/RequestParams";
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const styles = theme => ({ const styles = theme => ({
...@@ -58,6 +59,10 @@ function renderCore(rawModelData, classes, outsideData) { ...@@ -58,6 +59,10 @@ function renderCore(rawModelData, classes, outsideData) {
class UniversityGeneral extends Module { class UniversityGeneral extends Module {
apiParams = {
university: ({props}) => RequestParams.Builder.withId(props.univId).build(),
};
customRender() { customRender() {
const univInfos = this.getLatestReadData("university"); const univInfos = this.getLatestReadData("university");
const { classes } = this.props; const { classes } = this.props;
...@@ -96,7 +101,7 @@ const mapStateToProps = (state) => { ...@@ -96,7 +101,7 @@ const mapStateToProps = (state) => {
const mapDispatchToProps = (dispatch) => { const mapDispatchToProps = (dispatch) => {
return { return {
api: { api: {
university: ({ props }) => dispatch(getActions("universities").readOne(props.univId)), university: (params) => dispatch(getActions("universities").readOne(params)),
}, },
invalidateData: () => dispatch(getActions("universities").invalidateOne()) invalidateData: () => dispatch(getActions("universities").invalidateOne())
}; };
......
...@@ -13,6 +13,7 @@ import Scholarship from "./common/Scholarship"; ...@@ -13,6 +13,7 @@ import Scholarship from "./common/Scholarship";
import UniversityScholarshipEditor from "../editors/UniversityScholarshipEditor"; import UniversityScholarshipEditor from "../editors/UniversityScholarshipEditor";
import getActions from "../../../redux/api/getActions"; import getActions from "../../../redux/api/getActions";
import {withUnivInfo} from "../common/withUnivInfo"; import {withUnivInfo} from "../common/withUnivInfo";
import {RequestParams} from "../../../redux/api/RequestParams";
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const styles = theme => ({ const styles = theme => ({
...@@ -40,10 +41,9 @@ function renderCore(rawModelData, classes, outsideData) { ...@@ -40,10 +41,9 @@ function renderCore(rawModelData, classes, outsideData) {
class UniversityScholarships extends Module { class UniversityScholarships extends Module {
/** apiParams = {
* @override universityScholarships: ({props}) => RequestParams.Builder.withQueryParam("universities", props.univId).build(),
*/ };
getQueryParams = (propName) => propName === "universityScholarships" ? ({ universities: this.props.univId, }) : undefined;
customRender() { customRender() {
const univScholarshipsItems = this.getOnlyReadData("universityScholarships"), const univScholarshipsItems = this.getOnlyReadData("universityScholarships"),
...@@ -101,7 +101,7 @@ const mapStateToProps = (state) => { ...@@ -101,7 +101,7 @@ const mapStateToProps = (state) => {
const mapDispatchToProps = (dispatch) => { const mapDispatchToProps = (dispatch) => {
return { return {
api: { api: {
universityScholarships: ({ params }) => dispatch(getActions("universityScholarships").readAll(params)), universityScholarships: (params) => dispatch(getActions("universityScholarships").readAll(params)),
}, },