finsignal-feed-explore 1.1.1 → 1.2.0

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.
@@ -41,5 +41,7 @@ export interface FeedListProps {
41
41
  items?: FeedItem[];
42
42
  onItemClick?: (item: FeedItem) => void;
43
43
  className?: string;
44
+ feedApiUrl?: string;
45
+ useMockData?: boolean;
44
46
  }
45
- export declare function FeedList({ feedType, items, onItemClick, className }: FeedListProps): import("react/jsx-runtime").JSX.Element;
47
+ export declare function FeedList({ feedType, items: itemsProp, onItemClick, className, feedApiUrl, useMockData }: FeedListProps): import("react/jsx-runtime").JSX.Element;
package/dist/NewsFeed.js CHANGED
@@ -1,4 +1,14 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ import * as React from 'react';
2
12
  import { NewsSnippet } from './snippets/NewsSnippet';
3
13
  import './newsfeed.css';
4
14
  // Моковые данные в формате FinSignal Feed
@@ -178,7 +188,41 @@ function formatTimeAgo(dateString) {
178
188
  return `${Math.floor(diff / 3600)} ч назад`;
179
189
  return `${Math.floor(diff / 86400)} дн назад`;
180
190
  }
181
- export function FeedList({ feedType = 'trending', items = mockFeedItems, onItemClick, className = '' }) {
191
+ export function FeedList({ feedType = 'trending', items: itemsProp, onItemClick, className = '', feedApiUrl = 'https://explore-gateway.changesandbox.ru', useMockData = false }) {
192
+ const [items, setItems] = React.useState(itemsProp || mockFeedItems);
193
+ const [loading, setLoading] = React.useState(false);
194
+ const [error, setError] = React.useState(null);
195
+ // Загрузка новостей с API
196
+ React.useEffect(() => {
197
+ if (useMockData || itemsProp) {
198
+ setItems(itemsProp || mockFeedItems);
199
+ return;
200
+ }
201
+ const fetchNews = () => __awaiter(this, void 0, void 0, function* () {
202
+ setLoading(true);
203
+ setError(null);
204
+ try {
205
+ const response = yield fetch(`${feedApiUrl}/api/feed/${feedType}`);
206
+ if (!response.ok) {
207
+ throw new Error(`HTTP error! status: ${response.status}`);
208
+ }
209
+ const data = yield response.json();
210
+ // Преобразуем данные из API в формат FeedItem
211
+ const newsItems = data.items || data;
212
+ setItems(newsItems);
213
+ }
214
+ catch (err) {
215
+ console.error('Error fetching news:', err);
216
+ setError(err instanceof Error ? err.message : 'Failed to fetch news');
217
+ // Fallback на моки при ошибке
218
+ setItems(mockFeedItems);
219
+ }
220
+ finally {
221
+ setLoading(false);
222
+ }
223
+ });
224
+ fetchNews();
225
+ }, [feedApiUrl, feedType, useMockData, itemsProp]);
182
226
  const getTypeLabel = (type) => {
183
227
  const labels = {
184
228
  signal: 'Сигнал',
@@ -203,15 +247,28 @@ export function FeedList({ feedType = 'trending', items = mockFeedItems, onItemC
203
247
  };
204
248
  return colors[type] || colors.post;
205
249
  };
206
- return (_jsx("div", { className: `feed-list ${className}`, children: items.map((item) => {
207
- var _a, _b, _c, _d;
208
- // Рендерим news items через NewsSnippet
209
- if (item.type === 'news' && item.title && item.body) {
210
- return (_jsx(NewsSnippet, { id: item.content_id, title: item.title, content: item.body, recommendation: (_a = item.metadata.news) === null || _a === void 0 ? void 0 : _a.recommendation, stocks: (_b = item.metadata.news) === null || _b === void 0 ? void 0 : _b.stocks, onPress: () => onItemClick === null || onItemClick === void 0 ? void 0 : onItemClick(item), draggable: true, onDragStart: () => {
211
- console.log('Dragging news:', item.title);
212
- } }, item.content_id));
213
- }
214
- // Для остальных типов оставляем обычный рендеринг
215
- return (_jsxs("div", { className: "feed-item", onClick: () => onItemClick === null || onItemClick === void 0 ? void 0 : onItemClick(item), children: [_jsxs("div", { className: "feed-item-header", children: [_jsx("span", { className: "feed-type-badge", style: { backgroundColor: getTypeColor(item.type) }, children: getTypeLabel(item.type) }), _jsx("span", { className: "feed-time", children: formatTimeAgo(item.created_at) })] }), item.title && _jsx("h3", { className: "feed-title", children: item.title }), item.body && _jsx("p", { className: "feed-body", children: item.body }), item.metadata.signal && (_jsxs("div", { className: "feed-signal-metrics", children: [_jsxs("div", { className: "signal-stock", children: [_jsx("span", { className: "signal-symbol", children: item.metadata.signal.symbol }), _jsx("span", { className: "signal-company", children: item.metadata.signal.companyName })] }), _jsxs("div", { className: "signal-prices", children: [_jsxs("div", { className: "signal-price-item", children: [_jsx("span", { className: "label", children: "Entry:" }), _jsx("span", { className: "value", children: item.metadata.signal.metrics.entry })] }), _jsxs("div", { className: "signal-price-item", children: [_jsx("span", { className: "label", children: "TP:" }), _jsx("span", { className: "value green", children: item.metadata.signal.metrics.takeProfit })] }), _jsxs("div", { className: "signal-price-item", children: [_jsx("span", { className: "label", children: "SL:" }), _jsx("span", { className: "value red", children: item.metadata.signal.metrics.stopLoss })] })] })] })), ((_c = item.metadata.news) === null || _c === void 0 ? void 0 : _c.stocks) && (_jsx("div", { className: "feed-stocks", children: item.metadata.news.stocks.map((stock, idx) => (_jsxs("div", { className: "stock-card", children: [_jsx("span", { className: "stock-symbol", children: stock.symbol }), _jsx("span", { className: "stock-price", children: stock.price }), _jsx("span", { className: `stock-change ${stock.changeType}`, children: stock.change })] }, idx))) })), ((_d = item.metadata.ai_categorization) === null || _d === void 0 ? void 0 : _d.tags) && (_jsx("div", { className: "feed-tags", children: item.metadata.ai_categorization.tags.map((tag, idx) => (_jsxs("span", { className: "feed-tag", children: ["#", tag] }, idx))) }))] }, item.content_id));
216
- }) }));
250
+ return (_jsxs("div", { className: `feed-list ${className}`, children: [loading && (_jsx("div", { style: {
251
+ textAlign: 'center',
252
+ padding: '20px',
253
+ color: '#6b7280',
254
+ fontSize: '14px'
255
+ }, children: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043D\u043E\u0432\u043E\u0441\u0442\u0435\u0439..." })), error && !loading && (_jsxs("div", { style: {
256
+ padding: '16px',
257
+ backgroundColor: '#fef2f2',
258
+ border: '1px solid #fecaca',
259
+ borderRadius: '8px',
260
+ color: '#991b1b',
261
+ fontSize: '14px',
262
+ marginBottom: '12px'
263
+ }, children: ["\u041E\u0448\u0438\u0431\u043A\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438: ", error, ". \u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u043C \u0442\u0435\u0441\u0442\u043E\u0432\u044B\u0435 \u043D\u043E\u0432\u043E\u0441\u0442\u0438."] })), !loading && items.map((item) => {
264
+ var _a, _b, _c, _d;
265
+ // Рендерим news items через NewsSnippet
266
+ if (item.type === 'news' && item.title && item.body) {
267
+ return (_jsx(NewsSnippet, { id: item.content_id, title: item.title, content: item.body, recommendation: (_a = item.metadata.news) === null || _a === void 0 ? void 0 : _a.recommendation, stocks: (_b = item.metadata.news) === null || _b === void 0 ? void 0 : _b.stocks, onPress: () => onItemClick === null || onItemClick === void 0 ? void 0 : onItemClick(item), draggable: true, onDragStart: () => {
268
+ console.log('Dragging news:', item.title);
269
+ } }, item.content_id));
270
+ }
271
+ // Для остальных типов оставляем обычный рендеринг
272
+ return (_jsxs("div", { className: "feed-item", onClick: () => onItemClick === null || onItemClick === void 0 ? void 0 : onItemClick(item), children: [_jsxs("div", { className: "feed-item-header", children: [_jsx("span", { className: "feed-type-badge", style: { backgroundColor: getTypeColor(item.type) }, children: getTypeLabel(item.type) }), _jsx("span", { className: "feed-time", children: formatTimeAgo(item.created_at) })] }), item.title && _jsx("h3", { className: "feed-title", children: item.title }), item.body && _jsx("p", { className: "feed-body", children: item.body }), item.metadata.signal && (_jsxs("div", { className: "feed-signal-metrics", children: [_jsxs("div", { className: "signal-stock", children: [_jsx("span", { className: "signal-symbol", children: item.metadata.signal.symbol }), _jsx("span", { className: "signal-company", children: item.metadata.signal.companyName })] }), _jsxs("div", { className: "signal-prices", children: [_jsxs("div", { className: "signal-price-item", children: [_jsx("span", { className: "label", children: "Entry:" }), _jsx("span", { className: "value", children: item.metadata.signal.metrics.entry })] }), _jsxs("div", { className: "signal-price-item", children: [_jsx("span", { className: "label", children: "TP:" }), _jsx("span", { className: "value green", children: item.metadata.signal.metrics.takeProfit })] }), _jsxs("div", { className: "signal-price-item", children: [_jsx("span", { className: "label", children: "SL:" }), _jsx("span", { className: "value red", children: item.metadata.signal.metrics.stopLoss })] })] })] })), ((_c = item.metadata.news) === null || _c === void 0 ? void 0 : _c.stocks) && (_jsx("div", { className: "feed-stocks", children: item.metadata.news.stocks.map((stock, idx) => (_jsxs("div", { className: "stock-card", children: [_jsx("span", { className: "stock-symbol", children: stock.symbol }), _jsx("span", { className: "stock-price", children: stock.price }), _jsx("span", { className: `stock-change ${stock.changeType}`, children: stock.change })] }, idx))) })), ((_d = item.metadata.ai_categorization) === null || _d === void 0 ? void 0 : _d.tags) && (_jsx("div", { className: "feed-tags", children: item.metadata.ai_categorization.tags.map((tag, idx) => (_jsxs("span", { className: "feed-tag", children: ["#", tag] }, idx))) }))] }, item.content_id));
273
+ })] }));
217
274
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "finsignal-feed-explore",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "News feed explorer components for React web applications",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",