@truedat/dd 4.28.3 → 4.28.7

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.
Files changed (72) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +6 -6
  3. package/src/api.js +8 -0
  4. package/src/components/DictionaryRoutes.js +27 -0
  5. package/src/components/EditDomainForm.js +1 -0
  6. package/src/components/GrantDateFilter.js +30 -0
  7. package/src/components/GrantFilters.js +28 -0
  8. package/src/components/GrantFiltersLoader.js +29 -0
  9. package/src/components/GrantSelectedFilters.js +63 -0
  10. package/src/components/Grants.js +54 -0
  11. package/src/components/GrantsLabelResults.js +32 -0
  12. package/src/components/GrantsLoader.js +47 -0
  13. package/src/components/GrantsPagination.js +14 -0
  14. package/src/components/GrantsSearch.js +51 -0
  15. package/src/components/GrantsTable.js +112 -0
  16. package/src/components/StructureGrantCart.js +16 -14
  17. package/src/components/StructureGrantCartCheckout.js +9 -9
  18. package/src/components/StructureSummary.js +5 -5
  19. package/src/components/StructureTabPane.js +3 -3
  20. package/src/components/StructureView.js +14 -6
  21. package/src/components/__tests__/GrantDateFilter.spec.js +11 -0
  22. package/src/components/__tests__/GrantsLabelResults.js +17 -0
  23. package/src/components/__tests__/GrantsLoader.spec.js +41 -0
  24. package/src/components/__tests__/GrantsTable.spec.js +185 -0
  25. package/src/components/__tests__/StructureGrantRequestButton.spec.js +20 -9
  26. package/src/components/__tests__/StructureSummary.spec.js +1 -1
  27. package/src/components/__tests__/__snapshots__/DictionaryRoutes.spec.js.snap +8 -0
  28. package/src/components/__tests__/__snapshots__/GrantDateFilter.spec.js.snap +16 -0
  29. package/src/components/__tests__/__snapshots__/GrantsLabelResults.js.snap +16 -0
  30. package/src/components/__tests__/__snapshots__/GrantsLoader.spec.js.snap +27 -0
  31. package/src/components/__tests__/__snapshots__/GrantsTable.spec.js.snap +231 -0
  32. package/src/components/index.js +4 -0
  33. package/src/messages/en.js +12 -2
  34. package/src/messages/es.js +12 -2
  35. package/src/reducers/__tests__/grantDateFilter.spec.js +54 -0
  36. package/src/reducers/__tests__/grantFilters.spec.js +37 -0
  37. package/src/reducers/__tests__/grantQuery.spec.js +113 -0
  38. package/src/reducers/__tests__/grants.spec.js +102 -0
  39. package/src/reducers/grantActiveFilters.js +48 -0
  40. package/src/reducers/grantCount.js +20 -0
  41. package/src/reducers/grantDateFilter.js +31 -0
  42. package/src/reducers/grantFilters.js +19 -0
  43. package/src/reducers/grantLoading.js +16 -0
  44. package/src/reducers/grantQuery.js +62 -0
  45. package/src/reducers/grantSelectedFilter.js +34 -0
  46. package/src/reducers/grants.js +24 -0
  47. package/src/reducers/grantsFilters.js +19 -0
  48. package/src/reducers/grantsPageSize.js +15 -0
  49. package/src/reducers/index.js +18 -0
  50. package/src/reducers/structureDateFilter.js +2 -2
  51. package/src/reducers/structureQuery.js +2 -2
  52. package/src/routines.js +20 -0
  53. package/src/sagas/__tests__/fetchGrantFilters.spec.js +97 -0
  54. package/src/sagas/__tests__/fetchGrants.spec.js +86 -0
  55. package/src/sagas/fetchGrantFilters.js +31 -0
  56. package/src/sagas/fetchGrants.js +26 -0
  57. package/src/sagas/index.js +6 -0
  58. package/src/selectors/__tests__/__snapshots__/getGrantsColumns.spec.js.snap +10 -0
  59. package/src/selectors/__tests__/getGrantAvailableFilters.spec.js +15 -0
  60. package/src/selectors/__tests__/getGrantSelectedFilterActiveValues.spec.js +16 -0
  61. package/src/selectors/__tests__/getGrantSelectedFilterValues.spec.js +15 -0
  62. package/src/selectors/__tests__/getGrantSelectedFilters.spec.js +15 -0
  63. package/src/selectors/__tests__/getGrantsColumns.spec.js +40 -0
  64. package/src/selectors/__tests__/getTabVisibility.spec.js +30 -30
  65. package/src/selectors/getGrantAvailableFilters.js +17 -0
  66. package/src/selectors/getGrantSelectedFilterActiveValues.js +8 -0
  67. package/src/selectors/getGrantSelectedFilterValues.js +13 -0
  68. package/src/selectors/getGrantSelectedFilters.js +7 -0
  69. package/src/selectors/getGrantsColumns.js +84 -8
  70. package/src/selectors/getStructureSelectedFilterValues.js +5 -3
  71. package/src/selectors/getTabVisibility.js +7 -7
  72. package/src/selectors/index.js +4 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.28.6] 2021-09-20
4
+
5
+ ### Added
6
+
7
+ - [TD-3950] My grants table
8
+
9
+ ## [4.28.4] 2021-09-15
10
+
11
+ ### Added
12
+
13
+ - [TD-3950] Grants table
14
+
3
15
  ## [4.28.0] 2021-09-10
4
16
 
5
17
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dd",
3
- "version": "4.28.3",
3
+ "version": "4.28.7",
4
4
  "description": "Truedat Web Data Dictionary",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -34,7 +34,7 @@
34
34
  "@testing-library/jest-dom": "^5.14.1",
35
35
  "@testing-library/react": "^12.0.0",
36
36
  "@testing-library/user-event": "^13.2.1",
37
- "@truedat/test": "4.28.3",
37
+ "@truedat/test": "4.28.7",
38
38
  "babel-jest": "^27.0.6",
39
39
  "babel-plugin-dynamic-import-node": "^2.3.3",
40
40
  "babel-plugin-lodash": "^3.3.4",
@@ -84,9 +84,9 @@
84
84
  ]
85
85
  },
86
86
  "dependencies": {
87
- "@truedat/auth": "4.28.3",
88
- "@truedat/core": "4.28.3",
89
- "@truedat/df": "4.28.3",
87
+ "@truedat/auth": "4.28.7",
88
+ "@truedat/core": "4.28.7",
89
+ "@truedat/df": "4.28.7",
90
90
  "lodash": "^4.17.21",
91
91
  "path-to-regexp": "^1.7.0",
92
92
  "prop-types": "^15.7.2",
@@ -107,5 +107,5 @@
107
107
  "react-dom": ">= 16.8.6 < 17",
108
108
  "semantic-ui-react": ">= 0.88.2 < 2.1"
109
109
  },
110
- "gitHead": "9e024e24bbd8c461ca5daabf16a4dbffa7e0a1a6"
110
+ "gitHead": "d5cfc6f850ec38066139c97836b75d2f21d61d54"
111
111
  }
package/src/api.js CHANGED
@@ -4,11 +4,15 @@ const API_DATA_STRUCTURES_CSV = "/api/data_structures/csv";
4
4
  const API_DATA_STRUCTURES_SEARCH = "/api/data_structures/search";
5
5
  const API_DATA_STRUCTURE_FILTERS_SEARCH = "/api/data_structure_filters/search";
6
6
  const API_DATA_STRUCTURE_VERSION = "/api/data_structures/:id/versions/:version";
7
+ const API_GRANT_FILTERS_SEARCH = "/api/grant_filters/search";
7
8
  const API_PROFILE_EXECUTION = "/api/profile_executions/:id";
8
9
  const API_GRANT_REQUEST = "/api/grant_request_groups";
10
+ const API_GRANTS_SEARCH = "/api/grants/search";
9
11
  const API_GRAPH = "/api/graphs/:id";
10
12
  const API_GRAPHS = "/api/graphs";
11
13
  const API_GRAPH_CSV = "/api/graphs/csv";
14
+ const API_MY_GRANT_FILTERS_SEARCH = "/api/grant_filters/search/mine";
15
+ const API_MY_GRANTS_SEARCH = "/api/grants/search/mine";
12
16
  const API_NODE = "/api/nodes/:id";
13
17
  const API_NODES = "/api/nodes";
14
18
  const API_PROFILE_GROUP = "/api/profile_execution_groups/:id";
@@ -40,10 +44,14 @@ export {
40
44
  API_DATA_STRUCTURE_FILTERS_SEARCH,
41
45
  API_DATA_STRUCTURE_VERSION,
42
46
  API_PROFILE_EXECUTION,
47
+ API_GRANT_FILTERS_SEARCH,
43
48
  API_GRANT_REQUEST,
49
+ API_GRANTS_SEARCH,
44
50
  API_GRAPH,
45
51
  API_GRAPHS,
46
52
  API_GRAPH_CSV,
53
+ API_MY_GRANTS_SEARCH,
54
+ API_MY_GRANT_FILTERS_SEARCH,
47
55
  API_NODE,
48
56
  API_NODES,
49
57
  API_PROFILE_GROUP,
@@ -9,6 +9,8 @@ import {
9
9
  STRUCTURE_TYPES,
10
10
  SYSTEMS,
11
11
  GRANTS_REQUESTS_CHECKOUT,
12
+ GRANTS,
13
+ MY_GRANTS,
12
14
  } from "@truedat/core/routes";
13
15
  import ProfileExecution from "./ProfileExecution";
14
16
  import ProfileExecutionBreadcrumbs from "./ProfileExecutionBreadcrumbs";
@@ -24,6 +26,9 @@ import StructureTypesRoutes from "./StructureTypesRoutes";
24
26
  import SystemsRoutes from "./SystemsRoutes";
25
27
  import SystemsLoader from "./SystemsLoader";
26
28
  import StructureGrantCartCheckout from "./StructureGrantCartCheckout";
29
+ import GrantFiltersLoader from "./GrantFiltersLoader";
30
+ import GrantsLoader from "./GrantsLoader";
31
+ import Grants from "./Grants";
27
32
 
28
33
  const TemplatesLoader = React.lazy(() =>
29
34
  import("@truedat/df/templates/components/TemplatesLoader")
@@ -69,6 +74,28 @@ export const DictionaryRoutes = () => {
69
74
  path={GRANTS_REQUESTS_CHECKOUT}
70
75
  render={() => <StructureGrantCartCheckout />}
71
76
  />
77
+ <Route
78
+ path={GRANTS}
79
+ render={() => (
80
+ <>
81
+ <GrantsLoader />
82
+ <GrantFiltersLoader />
83
+ <Grants />
84
+ </>
85
+ )}
86
+ />
87
+ <Route
88
+ path={MY_GRANTS}
89
+ render={() => {
90
+ return (
91
+ <>
92
+ <GrantsLoader onlyMyGrants />
93
+ <GrantFiltersLoader onlyMyGrants />
94
+ <Grants onlyMyGrants />
95
+ </>
96
+ );
97
+ }}
98
+ />
72
99
  <Route path={STRUCTURE_TAGS} render={() => <StructureTagsRoutes />} />
73
100
  <Route path={STRUCTURE_TYPES} render={() => <StructureTypesRoutes />} />
74
101
  <Route
@@ -27,6 +27,7 @@ export const EditDomainForm = ({ title, updateStructure, structure }) => {
27
27
  <Container style={{ width: "400px" }}>
28
28
  <Header as="h2" content={title} />
29
29
  <DomainDropdownSelector
30
+ clearable={false}
30
31
  onChange={handleDomainSelected}
31
32
  name="domain"
32
33
  value={domainId || structure?.domain_id}
@@ -0,0 +1,30 @@
1
+ import React from "react";
2
+ import { propOr } from "lodash/fp";
3
+ import PropTypes from "prop-types";
4
+ import { FormattedMessage } from "react-intl";
5
+ import { connect } from "react-redux";
6
+ import DateRangeFilter from "@truedat/core/components/DateRangeFilter";
7
+ import { applyGrantDateFilter } from "../routines";
8
+
9
+ export const GrantDateFilter = ({ active, applyGrantDateFilter, ...props }) =>
10
+ active ? (
11
+ <>
12
+ <DateRangeFilter
13
+ label={<FormattedMessage id="grant.start_date" />}
14
+ name="start_date,end_date"
15
+ onChange={applyGrantDateFilter}
16
+ defaultValues={props}
17
+ />
18
+ </>
19
+ ) : null;
20
+
21
+ GrantDateFilter.propTypes = {
22
+ active: PropTypes.bool,
23
+ applyGrantDateFilter: PropTypes.func,
24
+ };
25
+
26
+ export const mapStateToProps = propOr({}, "grantDateFilter");
27
+
28
+ export default connect(mapStateToProps, { applyGrantDateFilter })(
29
+ GrantDateFilter
30
+ );
@@ -0,0 +1,28 @@
1
+ import React from "react";
2
+ import { connect } from "react-redux";
3
+ import { bindActionCreators } from "redux";
4
+ import { addGrantFilter, resetGrantFilters } from "../routines";
5
+ import { getGrantAvailableFilters } from "../selectors";
6
+
7
+ const AvailableFilters = React.lazy(() =>
8
+ import("@truedat/core/components/AvailableFilters")
9
+ );
10
+
11
+ const mapStateToProps = (state) => {
12
+ return {
13
+ filters: getGrantAvailableFilters(state),
14
+ disabled: state.grantFiltersLoading,
15
+ loading: state.grantFiltersLoading,
16
+ };
17
+ };
18
+
19
+ const mapDispatchToProps = (dispatch) =>
20
+ bindActionCreators(
21
+ {
22
+ addFilter: addGrantFilter,
23
+ resetFilters: resetGrantFilters,
24
+ },
25
+ dispatch
26
+ );
27
+
28
+ export default connect(mapStateToProps, mapDispatchToProps)(AvailableFilters);
@@ -0,0 +1,29 @@
1
+ import { connect } from "react-redux";
2
+ import { bindActionCreators } from "redux";
3
+ import { FiltersLoader } from "@truedat/core/components";
4
+ import { makeActiveFiltersSelector } from "@truedat/core/selectors";
5
+ import { clearGrantFilters, fetchGrantFilters } from "../routines";
6
+
7
+ const mapDispatchToProps = (dispatch, props) => {
8
+ const { onlyMyGrants } = props;
9
+ const fetchMyGrantsFilters = (payload) => {
10
+ return fetchGrantFilters({ payload, onlyMyGrants });
11
+ };
12
+ return bindActionCreators(
13
+ { clearFilters: clearGrantFilters, fetchFilters: fetchMyGrantsFilters },
14
+ dispatch
15
+ );
16
+ };
17
+
18
+ const makeMapStateToProps = ({}) => {
19
+ const activeFiltersSelector = makeActiveFiltersSelector("grantActiveFilters");
20
+ const mapStateToProps = (state, props) => {
21
+ return {
22
+ selectedFilter: state.grantSelectedFilter,
23
+ filters: activeFiltersSelector(state, props),
24
+ };
25
+ };
26
+ return mapStateToProps;
27
+ };
28
+
29
+ export default connect(makeMapStateToProps, mapDispatchToProps)(FiltersLoader);
@@ -0,0 +1,63 @@
1
+ import _ from "lodash/fp";
2
+ import { bindActionCreators } from "redux";
3
+ import { connect } from "react-redux";
4
+ import { makeOption } from "@truedat/core/services/i18n";
5
+ import { SelectedFilters } from "@truedat/core/components";
6
+ import {
7
+ closeGrantFilter,
8
+ openGrantFilter,
9
+ removeGrantFilter,
10
+ resetGrantFilters,
11
+ toggleGrantFilterValue,
12
+ } from "../routines";
13
+ import {
14
+ getGrantSelectedFilterActiveValues,
15
+ getGrantSelectedFilters,
16
+ getGrantSelectedFilterValues,
17
+ } from "../selectors";
18
+
19
+ const translations = (formatMessage) => ({
20
+ "active.raw": (v) =>
21
+ formatMessage({ id: `filters.active.raw.${v}`, defaultMessage: v }),
22
+ "execution_result_info.result_text": (v) => formatMessage({ id: v }),
23
+ });
24
+
25
+ export const mapStateToProps = (state, ownProps) => {
26
+ const formatMessage = _.pathOr(_.prop("id"), "intl.formatMessage")(ownProps);
27
+ const { grantSelectedFilter: selectedFilter } = state;
28
+
29
+ const i18nValues = _.flow(
30
+ getGrantSelectedFilterValues,
31
+ _.map(makeOption(translations(formatMessage), selectedFilter))
32
+ )(state);
33
+
34
+ // const values = _.flow(
35
+ // getGrantSelectedFilterValues,
36
+ // _.map((v) => ({ text: v, value: v }))
37
+ // )(state);
38
+
39
+ // _.map(
40
+ // makeOption(translations(formatMessage, structureTypes), selectedFilter)
41
+ // )(selectedFilterValues),
42
+
43
+ return {
44
+ selectedFilter,
45
+ selectedFilters: getGrantSelectedFilters(state),
46
+ selectedFilterActiveValues: getGrantSelectedFilterActiveValues(state),
47
+ selectedFilterValues: i18nValues,
48
+ };
49
+ };
50
+
51
+ const mapDispatchToProps = (dispatch) =>
52
+ bindActionCreators(
53
+ {
54
+ closeFilter: closeGrantFilter,
55
+ openFilter: openGrantFilter,
56
+ removeFilter: removeGrantFilter,
57
+ resetFilters: resetGrantFilters,
58
+ toggleFilterValue: toggleGrantFilterValue,
59
+ },
60
+ dispatch
61
+ );
62
+
63
+ export default connect(mapStateToProps, mapDispatchToProps)(SelectedFilters);
@@ -0,0 +1,54 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { connect } from "react-redux";
4
+ import { Header, Icon, Segment, Dimmer, Loader } from "semantic-ui-react";
5
+ import { FormattedMessage } from "react-intl";
6
+
7
+ import GrantDateFilter from "./GrantDateFilter";
8
+ import GrantsSearch from "./GrantsSearch";
9
+ import GrantsTable from "./GrantsTable";
10
+ //import JobsLabelResults from "./JobsLabelResults";
11
+ import GrantsLabelResults from "./GrantsLabelResults";
12
+
13
+ import GrantSelectedFilters from "./GrantSelectedFilters";
14
+ import GrantsPagination from "./GrantsPagination";
15
+
16
+ export const Grants = ({ grantsLoading, onlyMyGrants }) => (
17
+ <Segment>
18
+ <Header as="h2">
19
+ <Icon circular name="cogs" />
20
+ <Header.Content>
21
+ <FormattedMessage
22
+ id={onlyMyGrants ? "grants.mine.header" : "grants.header"}
23
+ />
24
+ <Header.Subheader>
25
+ <FormattedMessage
26
+ id={onlyMyGrants ? "grants.mine.subheader" : "grants.subheader"}
27
+ />
28
+ </Header.Subheader>
29
+ </Header.Content>
30
+ </Header>
31
+ <Segment attached="bottom">
32
+ <GrantsSearch />
33
+ <GrantSelectedFilters />
34
+ <GrantDateFilter />
35
+ <Dimmer.Dimmable dimmed={grantsLoading}>
36
+ <Dimmer active={grantsLoading} inverted>
37
+ <Loader />
38
+ </Dimmer>
39
+ </Dimmer.Dimmable>
40
+ <GrantsLabelResults />
41
+ <GrantsTable onlyMyGrants={onlyMyGrants} />
42
+ <GrantsPagination />
43
+ </Segment>
44
+ </Segment>
45
+ );
46
+
47
+ Grants.propTypes = {
48
+ grantsLoading: PropTypes.bool,
49
+ onlyMyGrants: PropTypes.bool,
50
+ };
51
+
52
+ const mapStateToProps = ({ grantsLoading }) => ({ grantsLoading });
53
+
54
+ export default connect(mapStateToProps)(Grants);
@@ -0,0 +1,32 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { connect } from "react-redux";
4
+ import { FormattedMessage } from "react-intl";
5
+ import { Label } from "semantic-ui-react";
6
+
7
+ export const GrantsLabelResults = ({ grantCount, grantsLoading }) => {
8
+ return (
9
+ <Label className="grants-label-results">
10
+ {grantsLoading ? (
11
+ <FormattedMessage id="grants.searching" />
12
+ ) : (
13
+ <FormattedMessage
14
+ id="grants.retrieved.results"
15
+ values={{ count: grantCount }}
16
+ />
17
+ )}
18
+ </Label>
19
+ );
20
+ };
21
+
22
+ GrantsLabelResults.propTypes = {
23
+ grantCount: PropTypes.number,
24
+ grantsLoading: PropTypes.bool,
25
+ };
26
+
27
+ const mapStateToProps = ({ grantCount, grantsLoading }) => ({
28
+ grantCount,
29
+ grantsLoading,
30
+ });
31
+
32
+ export default connect(mapStateToProps)(GrantsLabelResults);
@@ -0,0 +1,47 @@
1
+ import { useEffect } from "react";
2
+ import PropTypes from "prop-types";
3
+ import { connect } from "react-redux";
4
+ import { makeSearchQuerySelector } from "@truedat/core/selectors";
5
+ import { clearGrants, fetchGrants } from "../routines";
6
+
7
+ export const GrantsLoader = ({
8
+ clearGrants,
9
+ fetchGrants,
10
+ payload,
11
+ onlyMyGrants = false,
12
+ }) => {
13
+ useEffect(() => {
14
+ return () => {
15
+ clearGrants();
16
+ };
17
+ }, [clearGrants]);
18
+ useEffect(() => {
19
+ fetchGrants({ payload, onlyMyGrants });
20
+ }, [payload, fetchGrants, onlyMyGrants]);
21
+ return null;
22
+ };
23
+
24
+ GrantsLoader.propTypes = {
25
+ clearGrants: PropTypes.func,
26
+ fetchGrants: PropTypes.func,
27
+ payload: PropTypes.object,
28
+ onlyMyGrants: PropTypes.bool,
29
+ };
30
+
31
+ const makeMapStateToProps = () => {
32
+ const searchQuerySelector = makeSearchQuerySelector(
33
+ "grantQuery",
34
+ "grantActiveFilters",
35
+ "grantDateFilter"
36
+ );
37
+ const mapStateToProps = (state, props) => {
38
+ return {
39
+ payload: searchQuerySelector(state, props),
40
+ };
41
+ };
42
+ return mapStateToProps;
43
+ };
44
+
45
+ export default connect(makeMapStateToProps, { clearGrants, fetchGrants })(
46
+ GrantsLoader
47
+ );
@@ -0,0 +1,14 @@
1
+ import { connect } from "react-redux";
2
+ import { bindActionCreators } from "redux";
3
+ import { Pagination } from "@truedat/core/components";
4
+ import { selectGrantPage } from "../routines";
5
+
6
+ const mapDispatchToProps = (dispatch) =>
7
+ bindActionCreators({ selectPage: selectGrantPage }, dispatch);
8
+
9
+ const mapStateToProps = ({ grantQuery, grantCount, grantsPageSize }) => ({
10
+ activePage: grantQuery?.page,
11
+ totalPages: Math.ceil(grantCount / grantsPageSize),
12
+ });
13
+
14
+ export default connect(mapStateToProps, mapDispatchToProps)(Pagination);
@@ -0,0 +1,51 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { connect } from "react-redux";
4
+ import { Button, Icon, Input } from "semantic-ui-react";
5
+ import { useIntl } from "react-intl";
6
+ import { searchGrants, toggleGrantDateFilter } from "../routines";
7
+ import GrantFilters from "./GrantFilters";
8
+
9
+ export const GrantsSearch = ({
10
+ query,
11
+ searchGrants,
12
+ grantDateFilter,
13
+ toggleGrantDateFilter,
14
+ }) => {
15
+ const { formatMessage } = useIntl();
16
+
17
+ return (
18
+ <Input
19
+ value={query}
20
+ onChange={(_e, data) => searchGrants({ query: data.value })}
21
+ iconPosition="left"
22
+ action
23
+ placeholder={formatMessage({ id: "structures.search.placeholder" })}
24
+ >
25
+ <Icon name="search" link />
26
+ <input />
27
+ <Button
28
+ icon="calendar alternate outline"
29
+ active={grantDateFilter?.active}
30
+ onClick={() => toggleGrantDateFilter()}
31
+ />
32
+ <GrantFilters />
33
+ </Input>
34
+ );
35
+ };
36
+
37
+ GrantsSearch.propTypes = {
38
+ query: PropTypes.string,
39
+ searchGrants: PropTypes.func,
40
+ grantDateFilter: PropTypes.object,
41
+ toggleGrantDateFilter: PropTypes.func,
42
+ };
43
+
44
+ const mapStateToProps = ({ grantQuery }) => ({
45
+ query: grantQuery?.query,
46
+ });
47
+
48
+ export default connect(mapStateToProps, {
49
+ searchGrants,
50
+ toggleGrantDateFilter,
51
+ })(GrantsSearch);
@@ -0,0 +1,112 @@
1
+ import _ from "lodash/fp";
2
+ import React, { useRef, useState } from "react";
3
+ import PropTypes from "prop-types";
4
+ import { useIntl } from "react-intl";
5
+ import { Table, Header, Icon } from "semantic-ui-react";
6
+ import { connect } from "react-redux";
7
+ import { columnDecoratorComponent } from "@truedat/core/services";
8
+ import { getSortInfo, sortColumn } from "@truedat/core/services/sort";
9
+ import { getGrantsColumns, getGrantsTableColumns } from "../selectors";
10
+ import { sortGrants } from "../routines";
11
+
12
+ export const GrantsTable = ({
13
+ columns,
14
+ grants,
15
+ grantsLoading,
16
+ sortGrants,
17
+ grantsSorting,
18
+ }) => {
19
+ const { formatMessage } = useIntl();
20
+ const filteredColumns = _.filter((c) => _.any(_.prop(c.name))(grants))(
21
+ columns
22
+ );
23
+
24
+ const [sortedColumn, setColumn] = useState(
25
+ _.prop("column")(getSortInfo(grantsSorting))
26
+ );
27
+ const [direction, setDirection] = useState(
28
+ _.prop("direction")(getSortInfo(grantsSorting))
29
+ );
30
+
31
+ return (
32
+ <>
33
+ {!_.isEmpty(grants) && (
34
+ <Table sortable selectable>
35
+ <Table.Header>
36
+ <Table.Row>
37
+ {columns.map((column, i) => {
38
+ return (
39
+ <Table.HeaderCell
40
+ key={i}
41
+ width={column.width}
42
+ content={formatMessage({
43
+ id: `grant.header.${column.name}`,
44
+ defaultMessage: column.name,
45
+ })}
46
+ sorted={
47
+ _.path("sort.name")(column) === sortedColumn
48
+ ? direction
49
+ : null
50
+ }
51
+ className={_.path("sort.name")(column) ? "" : "disabled"}
52
+ onClick={() => {
53
+ filteredColumns.includes(column)
54
+ ? sortColumn(
55
+ column,
56
+ sortGrants,
57
+ setDirection,
58
+ setColumn,
59
+ direction,
60
+ sortedColumn
61
+ )
62
+ : null;
63
+ }}
64
+ />
65
+ );
66
+ })}
67
+ </Table.Row>
68
+ </Table.Header>
69
+ <Table.Body>
70
+ {grants.map((grant, i) => (
71
+ <Table.Row key={i}>
72
+ {columns &&
73
+ columns.map((column, key) => (
74
+ <Table.Cell
75
+ key={key}
76
+ textAlign={column.textAlign}
77
+ content={columnDecoratorComponent(column)(grant)}
78
+ />
79
+ ))}
80
+ </Table.Row>
81
+ ))}
82
+ </Table.Body>
83
+ </Table>
84
+ )}
85
+ {_.isEmpty(grants) && !grantsLoading && (
86
+ <Header as="h4">
87
+ <Icon name="search" />
88
+ <Header.Content>
89
+ {formatMessage({ id: "grants.search.results.empty" })}
90
+ </Header.Content>
91
+ </Header>
92
+ )}
93
+ </>
94
+ );
95
+ };
96
+
97
+ GrantsTable.propTypes = {
98
+ columns: PropTypes.array,
99
+ grants: PropTypes.array,
100
+ grantsLoading: PropTypes.bool,
101
+ sortGrants: PropTypes.func,
102
+ grantsSorting: PropTypes.array,
103
+ };
104
+
105
+ const mapStateToProps = (state, { onlyMyGrants }) => ({
106
+ columns: getGrantsTableColumns({ ...state, onlyMyGrants }),
107
+ grants: state.grants,
108
+ grantsLoading: state.grantsLoading,
109
+ grantsSorting: _.path("grantQuery.sort")(state),
110
+ });
111
+
112
+ export default connect(mapStateToProps, { sortGrants })(GrantsTable);