@gravity-ui/blog-constructor 4.0.0-alpha.1 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/build/cjs/blocks/Feed/Feed.js +47 -37
  3. package/build/cjs/blocks/Feed/reducer.d.ts +0 -5
  4. package/build/cjs/blocks/Feed/reducer.js +1 -4
  5. package/build/cjs/blocks/Header/schema.d.ts +81 -0
  6. package/build/cjs/blocks/Media/schema.d.ts +81 -0
  7. package/build/cjs/blocks/YFM/YFM.js +1 -1
  8. package/build/cjs/components/FeedHeader/FeedHeader.js +2 -2
  9. package/build/cjs/components/FeedHeader/components/Controls/Controls.d.ts +2 -3
  10. package/build/cjs/components/FeedHeader/components/Controls/Controls.js +24 -16
  11. package/build/cjs/components/Paginator/Paginator.d.ts +1 -1
  12. package/build/cjs/components/Paginator/Paginator.js +2 -2
  13. package/build/cjs/components/Paginator/types.d.ts +0 -1
  14. package/build/cjs/components/PostInfo/components/Save.js +6 -1
  15. package/build/cjs/components/Posts/Posts.css +25 -0
  16. package/build/cjs/components/Posts/Posts.d.ts +0 -1
  17. package/build/cjs/components/Posts/Posts.js +5 -4
  18. package/build/cjs/components/Prompt/Prompt.css +61 -0
  19. package/build/cjs/components/Prompt/Prompt.d.ts +17 -0
  20. package/build/cjs/components/Prompt/Prompt.js +41 -0
  21. package/build/cjs/components/PromptSignIn/PromptSignIn.d.ts +10 -0
  22. package/build/cjs/components/PromptSignIn/PromptSignIn.js +35 -0
  23. package/build/cjs/components/PromptSignIn/hooks/usePromptSignInProps.d.ts +6 -0
  24. package/build/cjs/components/PromptSignIn/hooks/usePromptSignInProps.js +16 -0
  25. package/build/cjs/components/Search/Search.js +1 -1
  26. package/build/cjs/containers/BlogPage/BlogPage.d.ts +4 -1
  27. package/build/cjs/containers/BlogPage/BlogPage.js +56 -18
  28. package/build/cjs/contexts/LikesContext.d.ts +2 -0
  29. package/build/cjs/hooks/useOpenCloseTimer.d.ts +9 -0
  30. package/build/cjs/hooks/useOpenCloseTimer.js +30 -0
  31. package/build/cjs/i18n/index.d.ts +3 -1
  32. package/build/cjs/i18n/index.js +6 -0
  33. package/build/cjs/models/common.d.ts +5 -1
  34. package/build/cjs/schema/index.d.ts +162 -0
  35. package/build/cjs/utils/common.js +1 -1
  36. package/build/esm/blocks/Feed/Feed.js +47 -37
  37. package/build/esm/blocks/Feed/reducer.d.ts +0 -5
  38. package/build/esm/blocks/Feed/reducer.js +1 -4
  39. package/build/esm/blocks/Header/schema.d.ts +81 -0
  40. package/build/esm/blocks/Media/schema.d.ts +81 -0
  41. package/build/esm/blocks/YFM/YFM.js +1 -1
  42. package/build/esm/components/FeedHeader/FeedHeader.js +2 -2
  43. package/build/esm/components/FeedHeader/components/Controls/Controls.d.ts +2 -3
  44. package/build/esm/components/FeedHeader/components/Controls/Controls.js +25 -17
  45. package/build/esm/components/Paginator/Paginator.d.ts +1 -1
  46. package/build/esm/components/Paginator/Paginator.js +2 -2
  47. package/build/esm/components/Paginator/types.d.ts +0 -1
  48. package/build/esm/components/PostInfo/components/Save.js +6 -1
  49. package/build/esm/components/Posts/Posts.css +25 -0
  50. package/build/esm/components/Posts/Posts.d.ts +0 -1
  51. package/build/esm/components/Posts/Posts.js +5 -4
  52. package/build/esm/components/Prompt/Prompt.css +61 -0
  53. package/build/esm/components/Prompt/Prompt.d.ts +18 -0
  54. package/build/esm/components/Prompt/Prompt.js +35 -0
  55. package/build/esm/components/PromptSignIn/PromptSignIn.d.ts +10 -0
  56. package/build/esm/components/PromptSignIn/PromptSignIn.js +28 -0
  57. package/build/esm/components/PromptSignIn/hooks/usePromptSignInProps.d.ts +6 -0
  58. package/build/esm/components/PromptSignIn/hooks/usePromptSignInProps.js +12 -0
  59. package/build/esm/components/Search/Search.js +1 -1
  60. package/build/esm/containers/BlogPage/BlogPage.d.ts +4 -1
  61. package/build/esm/containers/BlogPage/BlogPage.js +33 -18
  62. package/build/esm/contexts/LikesContext.d.ts +2 -0
  63. package/build/esm/hooks/useOpenCloseTimer.d.ts +9 -0
  64. package/build/esm/hooks/useOpenCloseTimer.js +26 -0
  65. package/build/esm/i18n/index.d.ts +3 -1
  66. package/build/esm/i18n/index.js +6 -0
  67. package/build/esm/models/common.d.ts +5 -1
  68. package/build/esm/schema/index.d.ts +162 -0
  69. package/build/esm/utils/common.js +1 -1
  70. package/package.json +3 -6
  71. package/server/data/sanitizeMeta.d.ts +2 -0
  72. package/server/data/sanitizeMeta.js +2 -0
  73. package/server/data/transformPageContent.js +1 -1
  74. package/server/models/common.d.ts +5 -1
  75. package/build/cjs/blocks/YFM/__tests__/YFM.test.d.ts +0 -1
  76. package/build/cjs/blocks/YFM/__tests__/YFM.test.js +0 -16
  77. package/build/esm/blocks/YFM/__tests__/YFM.test.d.ts +0 -1
  78. package/build/esm/blocks/YFM/__tests__/YFM.test.js +0 -11
@@ -27,11 +27,10 @@ export const Feed = ({ image }) => {
27
27
  const { posts, totalCount, tags, services, pinnedPost, getPosts, pageCountForShowSupportButtons, } = useContext(FeedContext);
28
28
  const router = useContext(RouterContext);
29
29
  const handleAnalytics = useAnalytics(DefaultEventNames.ShowMore);
30
- const [{ errorLoad, errorShowMore, isFetching, isShowMoreFetching, isShowMoreVisible, lastLoadedCount, postCountOnPage, postsOnPage, pinnedPostOnPage, currentPage, queryParams, }, dispatch,] = useReducer(reducer, {
30
+ const [{ errorLoad, errorShowMore, isFetching, isShowMoreVisible, lastLoadedCount, postCountOnPage, postsOnPage, pinnedPostOnPage, currentPage, queryParams, }, dispatch,] = useReducer(reducer, {
31
31
  errorLoad: false,
32
32
  errorShowMore: false,
33
33
  isFetching: false,
34
- isShowMoreFetching: false,
35
34
  isShowMoreVisible: true,
36
35
  lastLoadedCount: (posts === null || posts === void 0 ? void 0 : posts.length) || 0,
37
36
  postCountOnPage: totalCount || 0,
@@ -46,36 +45,36 @@ export const Feed = ({ image }) => {
46
45
  const pageChange = (value) => {
47
46
  dispatch({ type: ActionTypes.PageChange, payload: value });
48
47
  };
49
- const handleChangeQueryParams = (value) => {
50
- dispatch({ type: ActionTypes.QueryParamsChange, payload: value });
51
- const hasFirstPageQuery = Object.keys(value).some((queryKey) => queryKey === PAGE_QUERY && value[queryKey] === FIRST_PAGE);
52
- if (hasFirstPageQuery) {
53
- // eslint-disable-next-line no-not-accumulator-reassign/no-not-accumulator-reassign
54
- value[PAGE_QUERY] = null;
55
- }
56
- router.updateQueryCallback(value);
48
+ const setIsFetching = (value) => {
49
+ dispatch({ type: ActionTypes.SetIsFetching, payload: value });
57
50
  };
58
- const handlePageChange = async (value) => {
59
- pageChange(value);
60
- handleChangeQueryParams({ page: value });
51
+ const setErrorLoad = (value) => {
52
+ dispatch({ type: ActionTypes.SetErrorLoad, payload: value });
61
53
  };
62
- const fetchData = useCallback(async (pageNumber) => {
63
- if (queryParams && getPosts) {
64
- const query = getFeedQueryParams(queryParams, pageNumber);
65
- const data = await getPosts(query);
54
+ const handleChangeQueryParams = useCallback((value) => {
55
+ dispatch({ type: ActionTypes.QueryParamsChange, payload: value });
56
+ const hasFirstPageQuery = Object.keys(value).some((queryKey) => queryKey === PAGE_QUERY && value[queryKey] === FIRST_PAGE);
57
+ const result = hasFirstPageQuery
58
+ ? Object.assign(Object.assign({}, value), { [PAGE_QUERY]: null }) : Object.assign({}, value);
59
+ router.updateQueryCallback(result);
60
+ }, [router]);
61
+ const fetchData = useCallback(async ({ page, query }) => {
62
+ if (query && getPosts) {
63
+ const queryParamsForRequest = getFeedQueryParams(Object.assign(Object.assign({}, queryParams), query), page);
64
+ const data = await getPosts(queryParamsForRequest);
66
65
  return data;
67
66
  }
68
67
  else {
69
68
  throw new Error('cant get request');
70
69
  }
71
70
  }, [getPosts, queryParams]);
72
- const setIsFetching = (value) => {
73
- dispatch({ type: ActionTypes.SetIsFetching, payload: value });
74
- };
75
- const fetchAndReplaceData = useCallback(async (pageNumber) => {
71
+ const handleLoad = useCallback(async ({ page, query }) => {
72
+ const pageNumber = Number(page || queryParams.page || DEFAULT_PAGE);
73
+ handleChangeQueryParams(query);
76
74
  try {
77
- dispatch({ type: ActionTypes.SetErrorLoad, payload: false });
78
- const fetchedData = await fetchData(pageNumber);
75
+ setErrorLoad(false);
76
+ setIsFetching(true);
77
+ const fetchedData = await fetchData({ page: pageNumber, query });
79
78
  if (fetchedData) {
80
79
  dispatch({
81
80
  type: ActionTypes.SetPosts,
@@ -89,22 +88,35 @@ export const Feed = ({ image }) => {
89
88
  }
90
89
  }
91
90
  catch (err) {
92
- dispatch({ type: ActionTypes.SetErrorLoad, payload: true });
91
+ setErrorLoad(true);
93
92
  }
94
93
  scrollOnPageChange(CONTAINER_ID);
95
94
  setIsFetching(false);
96
- }, [fetchData]);
95
+ }, [fetchData, handleChangeQueryParams, queryParams]);
96
+ const handlePageChange = async (value) => {
97
+ pageChange(value);
98
+ handleLoad({
99
+ page: value,
100
+ query: Object.assign(Object.assign({}, queryParams), { page: value }),
101
+ });
102
+ };
97
103
  const handleShowMore = async () => {
98
- dispatch({ type: ActionTypes.SetIsShowMoreFetching, payload: true });
99
104
  /**
100
105
  * @deprecated Metrika will be deleted after launch of analyticsEvents
101
106
  */
102
107
  metrika.reachGoal(MetrikaCounter.CrossSite, BlogMetrikaGoalIds.showMore);
103
108
  handleAnalytics();
109
+ const nextPage = currentPage + 1;
104
110
  try {
105
- const fetchedData = await fetchData(currentPage + 1);
111
+ setIsFetching(true);
112
+ const fetchedData = await fetchData({
113
+ page: nextPage,
114
+ query: {
115
+ page: nextPage,
116
+ },
117
+ });
106
118
  handleChangeQueryParams({
107
- page: currentPage + 1,
119
+ page: nextPage,
108
120
  });
109
121
  if (fetchedData) {
110
122
  dispatch({
@@ -112,7 +124,7 @@ export const Feed = ({ image }) => {
112
124
  payload: {
113
125
  posts: (postsOnPage !== null && postsOnPage !== void 0 ? postsOnPage : []).concat(fetchedData.posts),
114
126
  count: fetchedData.count,
115
- currentPage: currentPage + 1,
127
+ currentPage: nextPage,
116
128
  lastLoadedCount: fetchedData.posts.length,
117
129
  },
118
130
  });
@@ -121,13 +133,11 @@ export const Feed = ({ image }) => {
121
133
  catch (err) {
122
134
  dispatch({ type: ActionTypes.SetErrorShowMore, payload: true });
123
135
  }
124
- dispatch({ type: ActionTypes.SetIsShowMoreFetching, payload: false });
136
+ setIsFetching(false);
125
137
  };
126
- useEffect(() => {
127
- if (isFetching) {
128
- fetchAndReplaceData(Number(queryParams.page || DEFAULT_PAGE));
129
- }
130
- }, [fetchAndReplaceData, isFetching, queryParams.page]);
138
+ const handleOnErrorReload = useCallback(() => {
139
+ handleLoad({ page: currentPage, query: queryParams });
140
+ }, [currentPage, handleLoad, queryParams]);
131
141
  useEffect(() => {
132
142
  const loadedPostsCount = currentPage * perPageInQuery;
133
143
  dispatch({
@@ -145,10 +155,10 @@ export const Feed = ({ image }) => {
145
155
  icon: tag.icon && React.createElement(Icon, { data: tag.icon }),
146
156
  })), [tags]);
147
157
  return (React.createElement("div", null,
148
- React.createElement(FeedHeader, { verticalOffset: "s", tags: tagItems, services: serviceItems, setIsFetching: setIsFetching, handleChangeQuery: handleChangeQueryParams, queryParams: queryParams, background: {
158
+ React.createElement(FeedHeader, { verticalOffset: "s", tags: tagItems, services: serviceItems, handleLoadData: handleLoad, queryParams: queryParams, background: {
149
159
  fullWidth: true,
150
160
  url: image,
151
161
  disableCompress: true,
152
162
  } }),
153
- errorLoad ? (React.createElement(PostsError, { onButtonClick: () => fetchAndReplaceData(Number(queryParams.page || DEFAULT_PAGE)) })) : (React.createElement(Posts, { containerId: CONTAINER_ID, currentPage: currentPage, isShowMoreVisible: isShowMoreVisible, errorShowMore: errorShowMore, postCountOnPage: postCountOnPage, perPageInQuery: perPageInQuery, handleShowMore: handleShowMore, handlePageChange: handlePageChange, postsOnPage: postsOnPage, pinnedPostOnPage: pinnedPostOnPage, isFetching: isFetching, isShowMoreFetching: isShowMoreFetching, pageCountForShowSupportButtons: pageCountForShowSupportButtons }))));
163
+ errorLoad ? (React.createElement(PostsError, { onButtonClick: handleOnErrorReload })) : (React.createElement(Posts, { containerId: CONTAINER_ID, currentPage: currentPage, isShowMoreVisible: isShowMoreVisible, errorShowMore: errorShowMore, postCountOnPage: postCountOnPage, perPageInQuery: perPageInQuery, handleShowMore: handleShowMore, handlePageChange: handlePageChange, postsOnPage: postsOnPage, pinnedPostOnPage: pinnedPostOnPage, isFetching: isFetching, pageCountForShowSupportButtons: pageCountForShowSupportButtons }))));
154
164
  };
@@ -6,7 +6,6 @@ export declare enum ActionTypes {
6
6
  SetPosts = "setPosts",
7
7
  SetShowMore = "setShowMore",
8
8
  SetIsFetching = "setIsFetching",
9
- SetIsShowMoreFetching = "setIsShowMoreFetching",
10
9
  PageChange = "pageChange",
11
10
  QueryParamsChange = "queryParamsChange"
12
11
  }
@@ -15,7 +14,6 @@ export type State = {
15
14
  errorLoad: boolean;
16
15
  errorShowMore: boolean;
17
16
  isFetching: boolean;
18
- isShowMoreFetching: boolean;
19
17
  isShowMoreVisible: boolean;
20
18
  lastLoadedCount: number;
21
19
  pinnedPostOnPage?: PostData;
@@ -29,9 +27,6 @@ type Action = {
29
27
  } | {
30
28
  type: ActionTypes.SetIsFetching;
31
29
  payload: boolean;
32
- } | {
33
- type: ActionTypes.SetIsShowMoreFetching;
34
- payload: boolean;
35
30
  } | {
36
31
  type: ActionTypes.SetPosts;
37
32
  payload: {
@@ -6,7 +6,6 @@ export var ActionTypes;
6
6
  ActionTypes["SetPosts"] = "setPosts";
7
7
  ActionTypes["SetShowMore"] = "setShowMore";
8
8
  ActionTypes["SetIsFetching"] = "setIsFetching";
9
- ActionTypes["SetIsShowMoreFetching"] = "setIsShowMoreFetching";
10
9
  ActionTypes["PageChange"] = "pageChange";
11
10
  ActionTypes["QueryParamsChange"] = "queryParamsChange";
12
11
  })(ActionTypes || (ActionTypes = {}));
@@ -17,11 +16,9 @@ export const reducer = (state, { type, payload }) => {
17
16
  case ActionTypes.SetPosts:
18
17
  return Object.assign(Object.assign({}, state), { lastLoadedCount: payload.count, postCountOnPage: payload.count, pinnedPostOnPage: payload.pinnedPost, postsOnPage: payload.posts, currentPage: payload.page });
19
18
  case ActionTypes.SetShowMore:
20
- return Object.assign(Object.assign({}, state), { lastLoadedCount: payload.lastLoadedCount, postCountOnPage: payload.count, currentPage: payload.currentPage, postsOnPage: payload.posts, errorShowMore: false, isShowMoreFetching: true });
19
+ return Object.assign(Object.assign({}, state), { lastLoadedCount: payload.lastLoadedCount, postCountOnPage: payload.count, currentPage: payload.currentPage, postsOnPage: payload.posts, errorShowMore: false });
21
20
  case ActionTypes.SetIsFetching:
22
21
  return Object.assign(Object.assign({}, state), { isFetching: payload });
23
- case ActionTypes.SetIsShowMoreFetching:
24
- return Object.assign(Object.assign({}, state), { isShowMoreFetching: payload });
25
22
  case ActionTypes.PageChange:
26
23
  return Object.assign(Object.assign({}, state), { currentPage: payload, isFetching: true });
27
24
  case ActionTypes.SetErrorLoad:
@@ -287,6 +287,87 @@ export declare const Header: {
287
287
  type: string;
288
288
  })[];
289
289
  };
290
+ fullscreen: {
291
+ type: string;
292
+ };
293
+ analyticsEvents: {
294
+ anyOf: ({
295
+ type: string;
296
+ additionalProperties: {
297
+ type: string;
298
+ };
299
+ required: string[];
300
+ properties: {
301
+ name: {
302
+ type: string;
303
+ };
304
+ type: {
305
+ type: string;
306
+ };
307
+ counters: {
308
+ type: string;
309
+ additionalProperties: boolean;
310
+ required: never[];
311
+ properties: {
312
+ include: {
313
+ type: string;
314
+ items: {
315
+ type: string;
316
+ };
317
+ };
318
+ exclude: {
319
+ type: string;
320
+ items: {
321
+ type: string;
322
+ };
323
+ };
324
+ };
325
+ };
326
+ context: {
327
+ type: string;
328
+ };
329
+ };
330
+ } | {
331
+ type: string;
332
+ items: {
333
+ type: string;
334
+ additionalProperties: {
335
+ type: string;
336
+ };
337
+ required: string[];
338
+ properties: {
339
+ name: {
340
+ type: string;
341
+ };
342
+ type: {
343
+ type: string;
344
+ };
345
+ counters: {
346
+ type: string;
347
+ additionalProperties: boolean;
348
+ required: never[];
349
+ properties: {
350
+ include: {
351
+ type: string;
352
+ items: {
353
+ type: string;
354
+ };
355
+ };
356
+ exclude: {
357
+ type: string;
358
+ items: {
359
+ type: string;
360
+ };
361
+ };
362
+ };
363
+ };
364
+ context: {
365
+ type: string;
366
+ };
367
+ };
368
+ };
369
+ })[];
370
+ };
290
371
  };
291
372
  } | {
292
373
  type: string;
@@ -135,6 +135,87 @@ export declare const Media: {
135
135
  type: string;
136
136
  })[];
137
137
  };
138
+ fullscreen: {
139
+ type: string;
140
+ };
141
+ analyticsEvents: {
142
+ anyOf: ({
143
+ type: string;
144
+ additionalProperties: {
145
+ type: string;
146
+ };
147
+ required: string[];
148
+ properties: {
149
+ name: {
150
+ type: string;
151
+ };
152
+ type: {
153
+ type: string;
154
+ };
155
+ counters: {
156
+ type: string;
157
+ additionalProperties: boolean;
158
+ required: never[];
159
+ properties: {
160
+ include: {
161
+ type: string;
162
+ items: {
163
+ type: string;
164
+ };
165
+ };
166
+ exclude: {
167
+ type: string;
168
+ items: {
169
+ type: string;
170
+ };
171
+ };
172
+ };
173
+ };
174
+ context: {
175
+ type: string;
176
+ };
177
+ };
178
+ } | {
179
+ type: string;
180
+ items: {
181
+ type: string;
182
+ additionalProperties: {
183
+ type: string;
184
+ };
185
+ required: string[];
186
+ properties: {
187
+ name: {
188
+ type: string;
189
+ };
190
+ type: {
191
+ type: string;
192
+ };
193
+ counters: {
194
+ type: string;
195
+ additionalProperties: boolean;
196
+ required: never[];
197
+ properties: {
198
+ include: {
199
+ type: string;
200
+ items: {
201
+ type: string;
202
+ };
203
+ };
204
+ exclude: {
205
+ type: string;
206
+ items: {
207
+ type: string;
208
+ };
209
+ };
210
+ };
211
+ };
212
+ context: {
213
+ type: string;
214
+ };
215
+ };
216
+ };
217
+ })[];
218
+ };
138
219
  paddingTop: {
139
220
  type: string;
140
221
  enum: string[];
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import block from 'bem-cn-lite';
3
2
  import { YFMWrapper } from '@gravity-ui/page-constructor';
3
+ import block from 'bem-cn-lite';
4
4
  import { Wrapper } from '../../components/Wrapper/Wrapper';
5
5
  import { PaddingsDirections } from '../../models/paddings';
6
6
  const b = block('yfm');
@@ -4,7 +4,7 @@ import { block } from '../../utils/cn';
4
4
  import { Controls } from './components/Controls/Controls';
5
5
  import './FeedHeader.css';
6
6
  const b = block('feed-header');
7
- export const FeedHeader = ({ tags, services, setIsFetching, offset = 'default', background, theme = 'default', verticalOffset = 'l', className, handleChangeQuery, queryParams, }) => {
7
+ export const FeedHeader = ({ tags, services, handleLoadData, offset = 'default', background, theme = 'default', verticalOffset = 'l', className, queryParams, }) => {
8
8
  const backgroundThemed = background && getThemedValue(background, theme);
9
9
  return (React.createElement("header", { className: b('header', { ['has-background']: Boolean(background) }, className) },
10
10
  (backgroundThemed === null || backgroundThemed === void 0 ? void 0 : backgroundThemed.color) ? (React.createElement(FullWidthBackground, { style: { backgroundColor: backgroundThemed === null || backgroundThemed === void 0 ? void 0 : backgroundThemed.color }, theme: "rounded" })) : null,
@@ -14,5 +14,5 @@ export const FeedHeader = ({ tags, services, setIsFetching, offset = 'default',
14
14
  ? ''
15
15
  : backgroundThemed === null || backgroundThemed === void 0 ? void 0 : backgroundThemed.color,
16
16
  }, disableCompress: backgroundThemed === null || backgroundThemed === void 0 ? void 0 : backgroundThemed.disableCompress })) : null,
17
- React.createElement(Controls, { tags: tags, services: services, setIsFetching: setIsFetching, handleChangeQuery: handleChangeQuery, queryParams: queryParams }))));
17
+ React.createElement(Controls, { tags: tags, services: services, handleLoadData: handleLoadData, queryParams: queryParams }))));
18
18
  };
@@ -1,5 +1,5 @@
1
1
  import React, { ReactNode } from 'react';
2
- import { HandleChangeQueryParams, Query, SetQueryType } from '../../../../models/common';
2
+ import { FetchArgs, Query, SetQueryType } from '../../../../models/common';
3
3
  import './Controls.css';
4
4
  export type SelectItem = {
5
5
  content: string;
@@ -7,10 +7,9 @@ export type SelectItem = {
7
7
  icon?: ReactNode;
8
8
  };
9
9
  export type ControlsProps = {
10
- setIsFetching: (value: boolean) => void;
10
+ handleLoadData: (props: FetchArgs) => void;
11
11
  tags?: SelectItem[];
12
12
  services?: SelectItem[];
13
- handleChangeQuery: HandleChangeQueryParams;
14
13
  queryParams: Query;
15
14
  setQuery?: SetQueryType;
16
15
  };
@@ -10,7 +10,7 @@ import metrika from '../../../../counters/metrika.js';
10
10
  import { MetrikaCounter } from '../../../../counters/utils';
11
11
  import { Keyset, i18 } from '../../../../i18n';
12
12
  import { Save } from '../../../../icons/Save';
13
- import { DefaultEventNames, } from '../../../../models/common';
13
+ import { DefaultEventNames } from '../../../../models/common';
14
14
  import { block } from '../../../../utils/cn';
15
15
  import { Search } from '../../../Search/Search';
16
16
  import { renderFilter, renderOption, renderSwitcher } from './customRenders';
@@ -19,7 +19,7 @@ const b = block('feed-controls');
19
19
  const ICON_SIZE = 16;
20
20
  const DEFAULT_PAGE = 1;
21
21
  const VIRTUALIZATION_THRESHOLD = 1000;
22
- export const Controls = ({ setIsFetching, tags = [], services = [], handleChangeQuery, queryParams, }) => {
22
+ export const Controls = ({ handleLoadData, tags = [], services = [], queryParams, }) => {
23
23
  const { hasLikes } = useContext(LikesContext);
24
24
  const handleAnalyticsTag = useAnalytics(DefaultEventNames.Tag);
25
25
  const handleAnalyticsService = useAnalytics(DefaultEventNames.Service);
@@ -28,21 +28,25 @@ export const Controls = ({ setIsFetching, tags = [], services = [], handleChange
28
28
  const [savedOnly, setSavedOnly] = useState(savedOnlyInitial === 'true');
29
29
  const [search, setSearch] = useState(searchInitial);
30
30
  const handleSavedOnly = () => {
31
- handleChangeQuery({
32
- savedOnly: savedOnly ? '' : 'true',
33
- search: '',
34
- tags: '',
35
- page: DEFAULT_PAGE,
36
- services: '',
37
- });
38
31
  handleAnalyticsSaveOnly();
39
32
  setSavedOnly(!savedOnly);
40
- setIsFetching(true);
33
+ handleLoadData({
34
+ page: DEFAULT_PAGE,
35
+ query: {
36
+ savedOnly: savedOnly ? '' : 'true',
37
+ search: '',
38
+ tags: '',
39
+ page: DEFAULT_PAGE,
40
+ services: '',
41
+ },
42
+ });
41
43
  };
42
44
  const handleSearch = (searchValue) => {
43
- handleChangeQuery({ search: searchValue, page: DEFAULT_PAGE });
44
45
  setSearch(searchValue);
45
- setIsFetching(true);
46
+ handleLoadData({
47
+ page: DEFAULT_PAGE,
48
+ query: { search: searchValue, page: DEFAULT_PAGE },
49
+ });
46
50
  };
47
51
  const handleTagSelect = (selectedTags) => {
48
52
  /**
@@ -55,11 +59,13 @@ export const Controls = ({ setIsFetching, tags = [], services = [], handleChange
55
59
  theme: selectedTags[0],
56
60
  });
57
61
  const isEmptyTag = selectedTags.some((tag) => tag === 'empty');
58
- handleChangeQuery({
59
- tags: isEmptyTag ? '' : selectedTags[0],
62
+ handleLoadData({
60
63
  page: DEFAULT_PAGE,
64
+ query: {
65
+ tags: isEmptyTag ? '' : selectedTags[0],
66
+ page: DEFAULT_PAGE,
67
+ },
61
68
  });
62
- setIsFetching(true);
63
69
  };
64
70
  const handleServicesSelect = (selectedServices) => {
65
71
  const forMetrikaServices = services.filter((service) => {
@@ -76,8 +82,10 @@ export const Controls = ({ setIsFetching, tags = [], services = [], handleChange
76
82
  service: metrikaAsString,
77
83
  });
78
84
  const servicesAsString = selectedServices.join(',');
79
- handleChangeQuery({ services: servicesAsString, page: DEFAULT_PAGE });
80
- setIsFetching(true);
85
+ handleLoadData({
86
+ page: DEFAULT_PAGE,
87
+ query: { services: servicesAsString, page: DEFAULT_PAGE },
88
+ });
81
89
  };
82
90
  const tagsItems = useMemo(() => [{ value: 'empty', content: i18(Keyset.AllTags) }, ...tags], [tags]);
83
91
  const servicesItems = useMemo(() => (servicesInitial ? [...servicesInitial.split(',')] : []), [servicesInitial]);
@@ -1,3 +1,3 @@
1
1
  import { PaginatorProps } from './types';
2
2
  import './Paginator.css';
3
- export declare const Paginator: ({ itemsPerPage, totalItems, maxPages, page, className, loading, onPageChange, pageCountForShowSupportButtons, }: PaginatorProps) => JSX.Element | null;
3
+ export declare const Paginator: ({ itemsPerPage, totalItems, maxPages, page, className, onPageChange, pageCountForShowSupportButtons, }: PaginatorProps) => JSX.Element | null;
@@ -26,7 +26,7 @@ import { getPageConfigs, getPagesCount } from './utils';
26
26
  import './Paginator.css';
27
27
  const b = block('paginator');
28
28
  const DEFAULT_PAGE_COUNT_FOR_SHOW_SUPPORT_BUTTONS = 6;
29
- export const Paginator = ({ itemsPerPage, totalItems, maxPages, page, className, loading, onPageChange, pageCountForShowSupportButtons = DEFAULT_PAGE_COUNT_FOR_SHOW_SUPPORT_BUTTONS, }) => {
29
+ export const Paginator = ({ itemsPerPage, totalItems, maxPages, page, className, onPageChange, pageCountForShowSupportButtons = DEFAULT_PAGE_COUNT_FOR_SHOW_SUPPORT_BUTTONS, }) => {
30
30
  const [pagesCount, setPagesCount] = useState(getPagesCount({ itemsPerPage, totalItems, maxPages }));
31
31
  useEffect(() => {
32
32
  const count = getPagesCount({ itemsPerPage, totalItems, maxPages });
@@ -95,7 +95,7 @@ export const Paginator = ({ itemsPerPage, totalItems, maxPages, page, className,
95
95
  }
96
96
  const renderPaginatorItem = (item) => {
97
97
  const { key } = item, rest = __rest(item, ["key"]);
98
- return React.createElement(PaginatorItem, Object.assign({ key: `page_${key}` }, rest, { loading: loading }));
98
+ return React.createElement(PaginatorItem, Object.assign({ key: `page_${key}` }, rest));
99
99
  };
100
100
  return (React.createElement("div", { className: b('pagination') },
101
101
  page > 1 && (React.createElement("div", { className: b('pagination-block') },
@@ -15,7 +15,6 @@ export type PaginatorProps = {
15
15
  totalItems: number;
16
16
  itemsPerPage: number;
17
17
  maxPages: number;
18
- loading: boolean;
19
18
  onPageChange: (page: number) => void;
20
19
  pageCountForShowSupportButtons?: number;
21
20
  } & ClassNameProps;
@@ -25,7 +25,7 @@ const b = block('post-info');
25
25
  * @returns jsx
26
26
  */
27
27
  export const Save = ({ title, postId, hasUserLike, handleUserLike, metrikaGoal, size, theme, dataQa, }) => {
28
- const { toggleLike } = useContext(LikesContext);
28
+ const { toggleLike, isSignedInUser, requireSignIn } = useContext(LikesContext);
29
29
  const handleAnalytics = useAnalytics(DefaultEventNames.SaveButton);
30
30
  const isLikeable = Boolean(toggleLike);
31
31
  return (React.createElement("div", { className: b('item', { size }), onClick: (event) => {
@@ -36,6 +36,11 @@ export const Save = ({ title, postId, hasUserLike, handleUserLike, metrikaGoal,
36
36
  if (!isLikeable) {
37
37
  return;
38
38
  }
39
+ // Open Popup to ask the User to sign in first
40
+ if (!isSignedInUser && requireSignIn) {
41
+ requireSignIn(event);
42
+ return;
43
+ }
39
44
  postLikeStatus(postId, Boolean(hasUserLike));
40
45
  handleUserLike();
41
46
  metrika.reachGoal(MetrikaCounter.CrossSite, metrikaGoal);
@@ -1,9 +1,15 @@
1
1
  /* use this for style redefinitions to awoid problems with
2
2
  unpredictable css rules order in build */
3
+ .bc-posts {
4
+ position: relative;
5
+ }
3
6
  .bc-posts__cards-container, .bc-posts__pinned-container {
4
7
  padding-top: 24px;
5
8
  scroll-margin: 48px;
6
9
  }
10
+ .bc-posts__cards-container_isLoading {
11
+ opacity: 0.7;
12
+ }
7
13
  .bc-posts__pagination {
8
14
  display: flex;
9
15
  flex-direction: column;
@@ -25,4 +31,23 @@ unpredictable css rules order in build */
25
31
  }
26
32
  .bc-posts__paginator {
27
33
  padding-top: 12px;
34
+ }
35
+ .bc-posts__loaderContainer {
36
+ z-index: 6;
37
+ position: absolute;
38
+ top: 0;
39
+ left: 0;
40
+ width: 70%;
41
+ height: 100%;
42
+ background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0));
43
+ animation: shimmer 2s infinite linear;
44
+ }
45
+
46
+ @keyframes shimmer {
47
+ from {
48
+ transform: translateX(-200%);
49
+ }
50
+ to {
51
+ transform: translateX(300%);
52
+ }
28
53
  }
@@ -9,7 +9,6 @@ type PostCardProps = {
9
9
  postCountOnPage: number;
10
10
  perPageInQuery: number;
11
11
  isFetching: boolean;
12
- isShowMoreFetching: boolean;
13
12
  handleShowMore: (value?: MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => Promise<void> | void;
14
13
  handlePageChange: (value: number) => Promise<void> | void;
15
14
  postsOnPage?: PostData[];
@@ -8,8 +8,9 @@ import { PostCard } from '../PostCard/PostCard';
8
8
  import { PostsEmpty } from '../PostsEmpty/PostsEmpty';
9
9
  import './Posts.css';
10
10
  const b = block('posts');
11
- export const Posts = ({ containerId, pinnedPostOnPage, currentPage, postsOnPage, isShowMoreVisible, errorShowMore, postCountOnPage, perPageInQuery, isFetching, isShowMoreFetching, handleShowMore, handlePageChange, pageCountForShowSupportButtons, }) => (React.createElement("div", { className: b() },
12
- React.createElement("div", { id: containerId, className: b('cards-container') },
11
+ export const Posts = ({ containerId, pinnedPostOnPage, currentPage, postsOnPage, isShowMoreVisible, errorShowMore, postCountOnPage, perPageInQuery, isFetching, handleShowMore, handlePageChange, pageCountForShowSupportButtons, }) => (React.createElement("div", { className: b() },
12
+ isFetching && React.createElement("div", { className: b('loaderContainer') }),
13
+ React.createElement("div", { id: containerId, className: b('cards-container', { isLoading: isFetching }) },
13
14
  pinnedPostOnPage && currentPage === 1 && (React.createElement("div", { className: b('pinned-container') },
14
15
  React.createElement(PostCard, { post: pinnedPostOnPage, size: "m", fullWidth: true, showTag: true }))),
15
16
  (postsOnPage === null || postsOnPage === void 0 ? void 0 : postsOnPage.length) ? (React.createElement(CardLayoutBlock, { title: '', colSizes: {
@@ -18,9 +19,9 @@ export const Posts = ({ containerId, pinnedPostOnPage, currentPage, postsOnPage,
18
19
  md: 6,
19
20
  } }, postsOnPage === null || postsOnPage === void 0 ? void 0 : postsOnPage.map((post) => (React.createElement(PostCard, { key: post.id, post: post, showTag: true }))))) : (React.createElement(PostsEmpty, null))),
20
21
  React.createElement("div", { className: b('pagination') },
21
- Boolean(isShowMoreVisible && (postsOnPage === null || postsOnPage === void 0 ? void 0 : postsOnPage.length)) && (React.createElement(Button, { view: "outlined", size: "xl", className: b('more-button'), onClick: handleShowMore, loading: isShowMoreFetching }, i18(Keyset.ActionLoadMore))),
22
+ Boolean(isShowMoreVisible && (postsOnPage === null || postsOnPage === void 0 ? void 0 : postsOnPage.length)) && (React.createElement(Button, { view: "outlined", size: "xl", className: b('more-button'), onClick: handleShowMore }, i18(Keyset.ActionLoadMore))),
22
23
  errorShowMore && (React.createElement("div", { className: b('error-show-more') },
23
24
  React.createElement("div", null, i18(Keyset.ErrorTitle)),
24
25
  React.createElement("div", null, i18(Keyset.PostLoadError)))),
25
26
  Boolean(currentPage && postCountOnPage) && (React.createElement("div", { className: b('paginator') },
26
- React.createElement(Paginator, { onPageChange: handlePageChange, page: currentPage, totalItems: postCountOnPage, itemsPerPage: perPageInQuery, loading: isFetching, maxPages: Infinity, pageCountForShowSupportButtons: pageCountForShowSupportButtons }))))));
27
+ React.createElement(Paginator, { onPageChange: handlePageChange, page: currentPage, totalItems: postCountOnPage, itemsPerPage: perPageInQuery, maxPages: Infinity, pageCountForShowSupportButtons: pageCountForShowSupportButtons }))))));