@truedat/core 5.20.0 → 5.20.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/core",
3
- "version": "5.20.0",
3
+ "version": "5.20.1",
4
4
  "description": "Truedat Web Core",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -117,5 +117,5 @@
117
117
  "react-dom": ">= 16.8.6 < 17",
118
118
  "semantic-ui-react": ">= 2.0.3 < 2.2"
119
119
  },
120
- "gitHead": "3981bdf2fff50f0d8c79643c6f423dfdc7f5a57f"
120
+ "gitHead": "a7197e02a1b1a88c375fe044dee65c7e96ccd618"
121
121
  }
package/src/api.js CHANGED
@@ -1,6 +1,8 @@
1
1
  export const API_COMMENTS = "/api/business_concepts/comments";
2
+ export const API_LOCALE = "/api/locales/:id";
2
3
  export const API_LOCALE_MESSAGES = "/api/locales/:lang/messages";
3
4
  export const API_LOCALES = "/api/locales";
5
+ export const API_ALL_LOCALES = "/api/locales/all_locales";
4
6
  export const API_MESSAGE = "/api/messages/:id";
5
7
  export const API_MESSAGES = "/api/messages";
6
8
  export const API_REINDEX_GRANTS = "/api/grants/search/reindex_all";
@@ -0,0 +1,9 @@
1
+ import useSWR from "swr";
2
+ import { API_ALL_LOCALES } from "../api";
3
+ import { apiJson } from "../services/api";
4
+
5
+ export const useAllLocales = () => {
6
+ const { data, loading, error, mutate } = useSWR(API_ALL_LOCALES, apiJson);
7
+ const all_locales = data?.data?.data;
8
+ return { all_locales, error, loading, mutate };
9
+ };
@@ -1,9 +1,44 @@
1
+ import { compile } from "path-to-regexp";
1
2
  import useSWR from "swr";
2
- import { API_LOCALES } from "../api";
3
- import { apiJson } from "../services/api";
3
+ import useSWRMutations from "swr/mutation";
4
+ import { API_LOCALES, API_LOCALE } from "../api";
5
+ import {
6
+ apiJson,
7
+ apiJsonDelete,
8
+ apiJsonPatch,
9
+ apiJsonPost,
10
+ } from "../services/api";
11
+ import _ from "lodash/fp";
4
12
 
5
13
  export const useLocales = () => {
6
14
  const { data, error, mutate } = useSWR(API_LOCALES, apiJson);
7
15
  const locales = data?.data?.data;
8
16
  return { locales, error, loading: !error && !data, mutate };
9
17
  };
18
+
19
+ export const useLocalesUpdate = (id) => {
20
+ const toApiPath = compile(API_LOCALE);
21
+ const url = toApiPath({ id });
22
+ return useSWRMutations(url, (url, { arg }) => {
23
+ const { mutateData } = arg;
24
+ const payload = { id: arg.id, locale: arg };
25
+ apiJsonPatch(url, payload).then(() => mutateData());
26
+ });
27
+ };
28
+
29
+ export const useLocalesCreate = () => {
30
+ const url = API_LOCALES;
31
+
32
+ return useSWRMutations(url, (url, { arg }) => {
33
+ apiJsonPost(url, arg);
34
+ });
35
+ };
36
+
37
+ export const useLocalesDelete = (id) => {
38
+ const toApiPath = compile(API_LOCALE);
39
+ const url = toApiPath({ id });
40
+ return useSWRMutations(url, (url, { arg }) => {
41
+ const payload = { id: arg.id };
42
+ apiJsonDelete(url, payload);
43
+ });
44
+ };
@@ -1,6 +1,5 @@
1
1
  import { compile } from "path-to-regexp";
2
- import { mutate } from "swr";
3
- import useSWR from "swr";
2
+ import useSWR, { mutate } from "swr";
4
3
  import useSWRMutations from "swr/mutation";
5
4
  import {
6
5
  API_LOCALE_MESSAGES,
@@ -0,0 +1,205 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import PropTypes from "prop-types";
3
+ import { useIntl, FormattedMessage } from "react-intl";
4
+ import _ from "lodash/fp";
5
+ import {
6
+ Button,
7
+ Dropdown,
8
+ Form,
9
+ Icon,
10
+ Input,
11
+ Table,
12
+ TableBody,
13
+ TableCell,
14
+ TableHeader,
15
+ TableRow,
16
+ } from "semantic-ui-react";
17
+ import { ConfirmModal } from "@truedat/core/components";
18
+ import { useAllLocales } from "../../hooks/useAllLocales";
19
+ import {
20
+ useLocalesCreate,
21
+ useLocalesDelete,
22
+ useLocalesUpdate,
23
+ } from "../../hooks/useLocales";
24
+
25
+ const LanguajeRow = ({ code, local, name, config, mutate }) => {
26
+ const { formatMessage } = useIntl();
27
+ const { trigger } = useLocalesUpdate(config.id);
28
+ const { trigger: triggerDelete } = useLocalesDelete(config.id);
29
+
30
+ const handleChange = (data) => {
31
+ const { name, checked } = data;
32
+ const newConfig = {
33
+ ...config,
34
+ [name]: !checked,
35
+ };
36
+ trigger({ ...newConfig, mutateData: mutate });
37
+ };
38
+
39
+ const handleDelete = () => {
40
+ triggerDelete(config).then(() => {
41
+ mutate();
42
+ });
43
+ };
44
+
45
+ return (
46
+ <TableRow>
47
+ <TableCell>
48
+ {_.upperCase(code)} | {local} ( {name} )
49
+ </TableCell>
50
+ <TableCell textAlign="center">
51
+ <Input
52
+ type="checkbox"
53
+ name="is_required"
54
+ checked={config.is_required}
55
+ disabled={config.is_default}
56
+ onChange={(_e, data) => handleChange(data)}
57
+ />
58
+ </TableCell>
59
+ <TableCell textAlign="center">
60
+ <Input
61
+ id={`radio-${code}`}
62
+ type="radio"
63
+ name="is_default"
64
+ checked={config.is_default}
65
+ onChange={(_e, data) => handleChange(data)}
66
+ />
67
+ </TableCell>
68
+ <TableCell>
69
+ <ConfirmModal
70
+ icon="trash"
71
+ trigger={
72
+ <Icon
73
+ className="lang-manager-delete"
74
+ name="trash alternate outline"
75
+ color="red"
76
+ disabled={config.is_default || ["es", "en"].includes(code)}
77
+ />
78
+ }
79
+ header={formatMessage({
80
+ id: "i18n.messages.locale.delete.confirmation.header",
81
+ })}
82
+ content={formatMessage({
83
+ id: "i18n.messages.locale.delete.confirmation.content",
84
+ })}
85
+ onConfirm={() => handleDelete()}
86
+ />
87
+ </TableCell>
88
+ </TableRow>
89
+ );
90
+ };
91
+
92
+ LanguajeRow.propTypes = {
93
+ code: PropTypes.string,
94
+ local: PropTypes.string,
95
+ name: PropTypes.string,
96
+ config: PropTypes.object,
97
+ mutate: PropTypes.func,
98
+ };
99
+
100
+ const Languages = ({ config, langs, mutate }) => {
101
+ const { formatMessage } = useIntl();
102
+ const { all_locales, loading, error } = useAllLocales();
103
+ const [newLocales, setNewLocales] = useState([]);
104
+ const { trigger } = useLocalesCreate();
105
+
106
+ const options = _.flow(
107
+ _.filter(({ code }) => {
108
+ return !langs.includes(code);
109
+ }),
110
+ _.map(({ code, name, local }) => {
111
+ return { text: `${local} (${name} | ${code})`, value: code };
112
+ })
113
+ )(all_locales);
114
+
115
+ const handleOnChange = ({ value }) => {
116
+ setNewLocales(value);
117
+ };
118
+
119
+ const handleSubmit = () => {
120
+ setNewLocales([]);
121
+ trigger({ locales: newLocales }).then(() => {
122
+ mutate();
123
+ });
124
+ };
125
+
126
+ return (
127
+ <>
128
+ <Form
129
+ onSubmit={() => {
130
+ handleSubmit();
131
+ }}
132
+ >
133
+ <Dropdown
134
+ className="lang-manager-dropdown"
135
+ placeholder={formatMessage({
136
+ id: "i18n.messages.locale.lang_select",
137
+ defaultMessage: "Select languaje",
138
+ })}
139
+ name="add-locales"
140
+ multiple={true}
141
+ search={true}
142
+ selection={true}
143
+ options={options}
144
+ clearable={true}
145
+ value={newLocales}
146
+ onChange={(_e, data) => {
147
+ handleOnChange(data);
148
+ }}
149
+ />
150
+ <Button
151
+ type="submit"
152
+ className="lang-manager-button"
153
+ disabled={_.isEmpty(newLocales)}
154
+ >
155
+ {formatMessage({
156
+ id: "i18n.messages.locale.add_lang",
157
+ })}
158
+ </Button>
159
+ </Form>
160
+ <Table collapsing striped>
161
+ <TableHeader>
162
+ <TableRow>
163
+ <TableCell></TableCell>
164
+ <TableCell textAlign="center">
165
+ {formatMessage({
166
+ id: "i18n.messages.locale.required",
167
+ })}
168
+ </TableCell>
169
+ <TableCell textAlign="center">
170
+ {formatMessage({
171
+ id: "i18n.messages.locale.default",
172
+ })}
173
+ </TableCell>
174
+ <TableCell></TableCell>
175
+ </TableRow>
176
+ </TableHeader>
177
+ <TableBody>
178
+ {_.flow(
179
+ _.filter((locale) => _.includes(locale.code)(langs)),
180
+ _.map(({ code, local, name }) => {
181
+ return (
182
+ <LanguajeRow
183
+ key={code}
184
+ code={code}
185
+ local={local}
186
+ name={name}
187
+ config={config[code]}
188
+ mutate={mutate}
189
+ />
190
+ );
191
+ })
192
+ )(all_locales)}
193
+ </TableBody>
194
+ </Table>
195
+ </>
196
+ );
197
+ };
198
+
199
+ Languages.propTypes = {
200
+ config: PropTypes.array,
201
+ langs: PropTypes.object,
202
+ mutate: PropTypes.func,
203
+ };
204
+
205
+ export default Languages;
@@ -104,15 +104,17 @@ export const MessageForm = ({ onSubmit, isSubmitting }) => {
104
104
  )}
105
105
  />
106
106
 
107
- {locales.map((lang, i) => (
108
- <LangForm
109
- key={i}
110
- control={control}
111
- lang={lang}
112
- errors={errors}
113
- formatMessage={formatMessage}
114
- />
115
- ))}
107
+ {locales
108
+ .filter(({ lang }) => lang === "en" || lang === "es")
109
+ .map((lang, i) => (
110
+ <LangForm
111
+ key={i}
112
+ control={control}
113
+ lang={lang}
114
+ errors={errors}
115
+ formatMessage={formatMessage}
116
+ />
117
+ ))}
116
118
 
117
119
  <div className="actions">
118
120
  <Button
@@ -18,12 +18,20 @@ import { useLocales } from "@truedat/core/hooks";
18
18
  import { I18N_MESSAGES_NEW } from "@truedat/core/routes";
19
19
  import { Pagination } from "@truedat/core/components";
20
20
  import MessagesTable from "./MessagesTable";
21
+ import Languages from "./Languages";
21
22
 
22
23
  const ITEMS_PER_PAGE = 30;
23
24
 
24
- export function MessagesContent({ locales, loading }) {
25
+ export function MessagesContent({ locales, loading, mutate }) {
25
26
  const langs = _.map("lang")(locales);
27
+
28
+ const langsConfig = _.flow(
29
+ _.map((locale) => _.omit("messages")(locale)),
30
+ _.groupBy("lang"),
31
+ _.mapValues(_.first)
32
+ )(locales);
26
33
  const [selectedLang, setSelectedLang] = useState(_.head(langs));
34
+ const [selectedManageView, setSelectedManageView] = useState(false);
27
35
  const [page, setPage] = useState(1);
28
36
  const [filter, setFilter] = useState("");
29
37
  const { formatMessage } = useIntl();
@@ -56,39 +64,59 @@ export function MessagesContent({ locales, loading }) {
56
64
  return (
57
65
  <>
58
66
  <Menu attached="top" secondary pointing tabular>
59
- {langs.map((lang, i) => (
60
- <Menu.Item
61
- key={i}
62
- active={lang === selectedLang}
63
- onClick={() => setSelectedLang(lang)}
64
- >
65
- <FormattedMessage id={`i18n.messages.locale.${lang}`} />
66
- </Menu.Item>
67
- ))}
67
+ <Menu.Item
68
+ key={0}
69
+ active={selectedManageView}
70
+ onClick={() => setSelectedManageView(true)}
71
+ >
72
+ <FormattedMessage id="i18n.messages.locale.manage" />
73
+ </Menu.Item>
74
+ {langs
75
+ .filter((lang) => lang === "en" || lang === "es")
76
+ .map((lang, i) => (
77
+ <Menu.Item
78
+ key={i}
79
+ active={lang === selectedLang && !selectedManageView}
80
+ onClick={() => {
81
+ setSelectedLang(lang);
82
+ setSelectedManageView(false);
83
+ }}
84
+ >
85
+ <FormattedMessage id={`i18n.messages.locale.${lang}`} />
86
+ </Menu.Item>
87
+ ))}
68
88
  </Menu>
69
89
  <Divider hidden />
70
- <SearchInput
71
- onChange={handleSearch}
72
- placeholder={formatMessage({ id: "i18n.messages.search.placeholder" })}
73
- value={filter}
74
- />
75
- <MessagesTable
76
- messages={paginatedMessages}
77
- locales={locales}
78
- loading={loading}
79
- />
80
- <Pagination
81
- totalPages={totalPages}
82
- activePage={page}
83
- selectPage={({ activePage }) => setPage(activePage)}
84
- />
90
+ {!selectedManageView ? (
91
+ <>
92
+ <SearchInput
93
+ onChange={handleSearch}
94
+ placeholder={formatMessage({
95
+ id: "i18n.messages.search.placeholder",
96
+ })}
97
+ value={filter}
98
+ />
99
+ <MessagesTable
100
+ messages={paginatedMessages}
101
+ locales={locales}
102
+ loading={loading}
103
+ />
104
+ <Pagination
105
+ totalPages={totalPages}
106
+ activePage={page}
107
+ selectPage={({ activePage }) => setPage(activePage)}
108
+ />
109
+ </>
110
+ ) : (
111
+ <Languages langs={langs} config={langsConfig} mutate={mutate} />
112
+ )}
85
113
  </>
86
114
  );
87
115
  }
88
116
 
89
117
  export default function Messages() {
90
118
  const { formatMessage } = useIntl();
91
- const { locales, loading } = useLocales();
119
+ const { locales, loading, mutate } = useLocales();
92
120
 
93
121
  return (
94
122
  <Segment>
@@ -116,7 +144,11 @@ export default function Messages() {
116
144
  to={I18N_MESSAGES_NEW}
117
145
  />
118
146
  {!loading ? (
119
- <MessagesContent locales={locales} loading={loading} />
147
+ <MessagesContent
148
+ locales={locales}
149
+ loading={loading}
150
+ mutate={mutate}
151
+ />
120
152
  ) : null}
121
153
  </Segment>
122
154
  </Segment>
@@ -1,9 +1,11 @@
1
1
  import React from "react";
2
2
  import { render } from "@truedat/test/render";
3
- import messages from "@truedat/core/messages";
3
+ import en from "@truedat/core/messages/en";
4
4
  import Messages from "../Messages";
5
5
 
6
- const renderOpts = { messages };
6
+ const renderOpts = {
7
+ messages: { en: { ...en, "i18n.messages.locale.manage": "manage" } },
8
+ };
7
9
 
8
10
  jest.mock("@truedat/core/hooks", () => ({
9
11
  useLocales: jest.fn(() => ({
@@ -55,6 +55,11 @@ exports[`<Messages /> matches the latest snapshot 1`] = `
55
55
  <div
56
56
  class="ui pointing secondary top attached tabular menu"
57
57
  >
58
+ <a
59
+ class="item"
60
+ >
61
+ manage
62
+ </a>
58
63
  <a
59
64
  class="active item"
60
65
  >