알림 목록 정렬 기능 추가
This commit is contained in:
@@ -23,9 +23,12 @@ import TradeNotificationGridLayoutPicker from './tradeNotification/TradeNotifica
|
||||
import {
|
||||
loadTradeNotificationGridPreset,
|
||||
loadTradeNotificationListLayout,
|
||||
loadTradeNotificationListSort,
|
||||
saveTradeNotificationGridPreset,
|
||||
saveTradeNotificationListLayout,
|
||||
saveTradeNotificationListSort,
|
||||
type TradeNotificationListLayout,
|
||||
type TradeNotificationListSort,
|
||||
} from '../utils/tradeNotificationListLayout';
|
||||
import {
|
||||
getTradeNotificationGridPreset,
|
||||
@@ -74,6 +77,24 @@ function fillBothSides(
|
||||
setFillSell({ market, price, side: 'sell', seq: seq + 1 });
|
||||
}
|
||||
|
||||
function sortNotifications(
|
||||
items: TradeNotificationItem[],
|
||||
sort: TradeNotificationListSort,
|
||||
): TradeNotificationItem[] {
|
||||
const arr = [...items];
|
||||
if (sort === 'market') {
|
||||
return arr.sort((a, b) => {
|
||||
const byMarket = a.market.localeCompare(b.market, 'ko');
|
||||
if (byMarket !== 0) return byMarket;
|
||||
return b.receivedAt - a.receivedAt;
|
||||
});
|
||||
}
|
||||
if (sort === 'oldest') {
|
||||
return arr.sort((a, b) => a.receivedAt - b.receivedAt);
|
||||
}
|
||||
return arr.sort((a, b) => b.receivedAt - a.receivedAt);
|
||||
}
|
||||
|
||||
export const TradeNotificationListPage: React.FC<Props> = ({
|
||||
theme,
|
||||
onGoToChart,
|
||||
@@ -96,6 +117,9 @@ export const TradeNotificationListPage: React.FC<Props> = ({
|
||||
} = useTradeNotification();
|
||||
|
||||
const [filter, setFilter] = useState<'all' | 'unread'>('all');
|
||||
const [listSort, setListSort] = useState<TradeNotificationListSort>(
|
||||
() => loadTradeNotificationListSort(),
|
||||
);
|
||||
const [listLayout, setListLayout] = useState<TradeNotificationListLayout>(
|
||||
() => loadTradeNotificationListLayout(),
|
||||
);
|
||||
@@ -226,6 +250,16 @@ export const TradeNotificationListPage: React.FC<Props> = ({
|
||||
? allNotifications.filter(n => !n.isRead)
|
||||
: allNotifications;
|
||||
|
||||
const sorted = useMemo(
|
||||
() => sortNotifications(filtered, listSort),
|
||||
[filtered, listSort],
|
||||
);
|
||||
|
||||
const handleListSortChange = useCallback((sort: TradeNotificationListSort) => {
|
||||
setListSort(sort);
|
||||
saveTradeNotificationListSort(sort);
|
||||
}, []);
|
||||
|
||||
const handleListLayoutChange = useCallback((layout: TradeNotificationListLayout) => {
|
||||
setListLayout(layout);
|
||||
saveTradeNotificationListLayout(layout);
|
||||
@@ -303,6 +337,29 @@ export const TradeNotificationListPage: React.FC<Props> = ({
|
||||
모두 읽음
|
||||
</button>
|
||||
)}
|
||||
<div className="tnl-filter tnl-sort-toggle" role="group" aria-label="목록 정렬">
|
||||
<button
|
||||
type="button"
|
||||
className={listSort === 'market' ? 'tnl-filter-btn--active' : ''}
|
||||
onClick={() => handleListSortChange('market')}
|
||||
>
|
||||
종목순
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={listSort === 'newest' ? 'tnl-filter-btn--active' : ''}
|
||||
onClick={() => handleListSortChange('newest')}
|
||||
>
|
||||
최신시간순
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={listSort === 'oldest' ? 'tnl-filter-btn--active' : ''}
|
||||
onClick={() => handleListSortChange('oldest')}
|
||||
>
|
||||
이전시간순
|
||||
</button>
|
||||
</div>
|
||||
<div className="tnl-toolbar-end">
|
||||
<div className="tnl-layout-toggle vtd-view-toggle" role="group" aria-label="목록 표시 방식">
|
||||
<button
|
||||
@@ -361,7 +418,7 @@ export const TradeNotificationListPage: React.FC<Props> = ({
|
||||
</div>
|
||||
|
||||
<div className={['tnl-list-wrap', !isListView ? 'tnl-list-wrap--grid' : ''].filter(Boolean).join(' ')}>
|
||||
{filtered.length === 0 ? (
|
||||
{sorted.length === 0 ? (
|
||||
<div className="tnl-empty">표시할 알림이 없습니다.</div>
|
||||
) : (
|
||||
<ul
|
||||
@@ -372,7 +429,7 @@ export const TradeNotificationListPage: React.FC<Props> = ({
|
||||
].filter(Boolean).join(' ')}
|
||||
style={!isListView ? { gridTemplateColumns: `repeat(${gridCols}, minmax(0, 1fr))` } : undefined}
|
||||
>
|
||||
{filtered.map(item => (
|
||||
{sorted.map(item => (
|
||||
<TradeNotificationListRow
|
||||
key={item.id}
|
||||
item={item}
|
||||
|
||||
@@ -35,6 +35,8 @@ export interface UiPreferences {
|
||||
listLayout?: 'list' | 'grid';
|
||||
/** 그리드형 열 배치 프리셋 id (tradeNotificationGridPresets) */
|
||||
gridPreset?: string;
|
||||
/** 목록 정렬 — market | newest | oldest */
|
||||
listSort?: 'market' | 'newest' | 'oldest';
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@ import {
|
||||
|
||||
export type TradeNotificationListLayout = 'list' | 'grid';
|
||||
|
||||
/** 알림 목록 정렬 */
|
||||
export type TradeNotificationListSort = 'market' | 'newest' | 'oldest';
|
||||
|
||||
export function loadTradeNotificationListLayout(): TradeNotificationListLayout {
|
||||
const v = getUiPreferences().tradeNotifications?.listLayout;
|
||||
return v === 'grid' ? 'grid' : 'list';
|
||||
@@ -25,3 +28,13 @@ export function loadTradeNotificationGridPreset(): TradeNotificationGridPresetId
|
||||
export function saveTradeNotificationGridPreset(preset: TradeNotificationGridPresetId): void {
|
||||
patchUiPreferences({ tradeNotifications: { gridPreset: preset } });
|
||||
}
|
||||
|
||||
export function loadTradeNotificationListSort(): TradeNotificationListSort {
|
||||
const v = getUiPreferences().tradeNotifications?.listSort;
|
||||
if (v === 'market' || v === 'oldest') return v;
|
||||
return 'newest';
|
||||
}
|
||||
|
||||
export function saveTradeNotificationListSort(sort: TradeNotificationListSort): void {
|
||||
patchUiPreferences({ tradeNotifications: { listSort: sort } });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user