Small calendar type dedupe (#4116)
* Small calendar type dedupe * Additional cleanups
This commit is contained in:
parent
31c1a887a4
commit
8881e459ce
@ -1,7 +1,7 @@
|
||||
// Copyright 2017-2020 @polkadot/app-calendar authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { EntryInfo } from './types';
|
||||
import type { EntryInfoTyped } from './types';
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
@ -14,23 +14,25 @@ interface Props {
|
||||
hour: number;
|
||||
index: number;
|
||||
minutes: number;
|
||||
scheduled: EntryInfo[];
|
||||
scheduled: EntryInfoTyped[];
|
||||
}
|
||||
|
||||
const MN_TO_MS = 60 * 1000;
|
||||
const HR_TO_MS = 60 * MN_TO_MS;
|
||||
|
||||
function filterEntries (date: Date, minutes: number, index: number, scheduled: EntryInfoTyped[]): EntryInfoTyped[] {
|
||||
const start = date.getTime() + (index * HR_TO_MS);
|
||||
const end = start + HR_TO_MS;
|
||||
const explicit = start + (minutes * MN_TO_MS);
|
||||
|
||||
return scheduled
|
||||
.filter(({ dateTime }) => dateTime >= explicit && dateTime < end)
|
||||
.sort((a, b) => (a.dateTime - b.dateTime) || a.type.localeCompare(b.type));
|
||||
}
|
||||
|
||||
function DayHour ({ className = '', date, hour, index, minutes, scheduled }: Props): React.ReactElement<Props> | null {
|
||||
const filtered = useMemo(
|
||||
(): EntryInfo[] => {
|
||||
const start = date.getTime() + (index * HR_TO_MS);
|
||||
const end = start + HR_TO_MS;
|
||||
const explicit = start + (minutes * MN_TO_MS);
|
||||
|
||||
return scheduled
|
||||
.filter(({ dateTime }) => dateTime >= explicit && dateTime < end)
|
||||
.sort((a, b) => (a.dateTime - b.dateTime) || a.type.localeCompare(b.type));
|
||||
},
|
||||
() => filterEntries(date, minutes, index, scheduled),
|
||||
[date, index, minutes, scheduled]
|
||||
);
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Copyright 2017-2020 @polkadot/app-calendar authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { EntryInfo } from './types';
|
||||
import type { EntryInfoTyped } from './types';
|
||||
|
||||
import React, { useMemo, useState, useCallback } from 'react';
|
||||
import styled from 'styled-components';
|
||||
@ -13,7 +13,7 @@ import { useTranslation } from './translate';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
item: EntryInfo;
|
||||
item: EntryInfoTyped;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
@ -21,41 +21,43 @@ function assertUnreachable (x: never): never {
|
||||
throw new Error('We cannot get here');
|
||||
}
|
||||
|
||||
function exportCalendar (date: Date, description: string): void {
|
||||
const startDate = dateCalendarFormat(date);
|
||||
// For now just add 1 hour for each event
|
||||
const endDate = dateCalendarFormat(new Date(new Date(date).setHours(new Date(date).getHours() + 1)));
|
||||
const calData =
|
||||
'BEGIN:VCALENDAR\n' +
|
||||
'CALSCALE:GREGORIAN\n' +
|
||||
'METHOD:PUBLISH\n' +
|
||||
'PRODID:-//Test Cal//EN\n' +
|
||||
'VERSION:2.0\n' +
|
||||
'BEGIN:VEVENT\n' +
|
||||
'UID:test-1\n' +
|
||||
'DTSTART;VALUE=DATE:' + startDate + '\n' +
|
||||
'DTEND;VALUE=DATE:' + endDate + '\n' +
|
||||
'SUMMARY:' + description + '\n' +
|
||||
'DESCRIPTION:' + description + '\n' +
|
||||
'END:VEVENT\n' +
|
||||
'END:VCALENDAR';
|
||||
const fileNameIcs = encodeURI(description) + '.ics';
|
||||
const data = new File([calData], fileNameIcs, { type: 'text/plain' });
|
||||
const anchor = window.document.createElement('a');
|
||||
|
||||
anchor.href = window.URL.createObjectURL(data);
|
||||
anchor.download = fileNameIcs;
|
||||
document.body.appendChild(anchor);
|
||||
anchor.click();
|
||||
document.body.removeChild(anchor);
|
||||
window.URL.revokeObjectURL(anchor.href);
|
||||
}
|
||||
|
||||
function DayItem ({ className, item: { date, info, type } }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [description, setDescription] = useState<string>('');
|
||||
|
||||
const _exportCal = useCallback(
|
||||
() => {
|
||||
const startDate = dateCalendarFormat(date);
|
||||
// For now just add 1 hour for each event
|
||||
const endDate = dateCalendarFormat(new Date(new Date(date).setHours(new Date(date).getHours() + 1)));
|
||||
const calData =
|
||||
'BEGIN:VCALENDAR\n' +
|
||||
'CALSCALE:GREGORIAN\n' +
|
||||
'METHOD:PUBLISH\n' +
|
||||
'PRODID:-//Test Cal//EN\n' +
|
||||
'VERSION:2.0\n' +
|
||||
'BEGIN:VEVENT\n' +
|
||||
'UID:test-1\n' +
|
||||
'DTSTART;VALUE=DATE:' + startDate + '\n' +
|
||||
'DTEND;VALUE=DATE:' + endDate + '\n' +
|
||||
'SUMMARY:' + description + '\n' +
|
||||
'DESCRIPTION:' + description + '\n' +
|
||||
'END:VEVENT\n' +
|
||||
'END:VCALENDAR';
|
||||
const fileNameIcs = encodeURI(description) + '.ics';
|
||||
const data = new File([calData], fileNameIcs, { type: 'text/plain' });
|
||||
const anchor = window.document.createElement('a');
|
||||
|
||||
anchor.href = window.URL.createObjectURL(data);
|
||||
anchor.download = fileNameIcs;
|
||||
document.body.appendChild(anchor);
|
||||
anchor.click();
|
||||
document.body.removeChild(anchor);
|
||||
window.URL.revokeObjectURL(anchor.href);
|
||||
},
|
||||
() => exportCalendar(date, description),
|
||||
[description, date]
|
||||
);
|
||||
|
||||
@ -180,7 +182,7 @@ export default React.memo(styled(DayItem)`
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
right: 1.5rem;
|
||||
|
||||
|
||||
.ui--Icon {
|
||||
width: 0.7rem;
|
||||
height: 0.7rem;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Copyright 2017-2020 @polkadot/app-calendar authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import BN from 'bn.js';
|
||||
import type BN from 'bn.js';
|
||||
|
||||
export type EntryType = 'councilElection' | 'councilMotion' | 'democracyDispatch' | 'democracyLaunch' | 'referendumDispatch' | 'referendumVote' | 'scheduler' | 'societyChallenge' | 'societyRotate'| 'stakingEpoch' | 'stakingEra' | 'stakingSlash' | 'treasurySpend';
|
||||
|
||||
@ -12,6 +12,9 @@ export interface EntryInfo {
|
||||
dateTime: number;
|
||||
info: string | BN | null;
|
||||
isPending?: boolean;
|
||||
}
|
||||
|
||||
export interface EntryInfoTyped extends EntryInfo {
|
||||
type: EntryType;
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
import type { DeriveCollectiveProposal, DeriveDispatch, DeriveReferendumExt, DeriveSessionProgress } from '@polkadot/api-derive/types';
|
||||
import type { Option } from '@polkadot/types';
|
||||
import type { BlockNumber, EraIndex, Scheduled, UnappliedSlash } from '@polkadot/types/interfaces';
|
||||
import type { EntryInfo, EntryType } from './types';
|
||||
import type { EntryInfo, EntryInfoTyped, EntryType } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { useEffect, useState } from 'react';
|
||||
@ -38,8 +38,7 @@ function createConstDurations (bestNumber: BlockNumber, blockTime: number, items
|
||||
...newDate(blocks, blockTime),
|
||||
blockNumber: bestNumber.add(blocks),
|
||||
blocks,
|
||||
info: null,
|
||||
type
|
||||
info: null
|
||||
}]];
|
||||
});
|
||||
}
|
||||
@ -58,8 +57,7 @@ function createCouncilMotions (bestNumber: BlockNumber, blockTime: number, motio
|
||||
...newDate(blocks, blockTime),
|
||||
blockNumber: votes.end,
|
||||
blocks,
|
||||
info: `${hashStr.substr(0, 6)}…${hashStr.substr(-4)}`,
|
||||
type: 'councilMotion'
|
||||
info: `${hashStr.substr(0, 6)}…${hashStr.substr(-4)}`
|
||||
};
|
||||
})
|
||||
.filter((item): item is EntryInfo => !!item)
|
||||
@ -74,8 +72,7 @@ function createDispatches (bestNumber: BlockNumber, blockTime: number, dispatche
|
||||
...newDate(blocks, blockTime),
|
||||
blockNumber: at,
|
||||
blocks,
|
||||
info: index,
|
||||
type: 'democracyDispatch'
|
||||
info: index
|
||||
}]];
|
||||
});
|
||||
}
|
||||
@ -89,16 +86,14 @@ function createReferendums (bestNumber: BlockNumber, blockTime: number, referend
|
||||
...newDate(voteBlocks, blockTime),
|
||||
blockNumber: bestNumber.add(voteBlocks),
|
||||
blocks: voteBlocks,
|
||||
info: index,
|
||||
type: 'referendumVote'
|
||||
info: index
|
||||
}]]);
|
||||
result.push(['referendumDispatch', [{
|
||||
...newDate(enactBlocks, blockTime),
|
||||
blockNumber: bestNumber.add(enactBlocks),
|
||||
blocks: enactBlocks,
|
||||
info: index,
|
||||
isPending: true,
|
||||
type: 'referendumDispatch'
|
||||
isPending: true
|
||||
}]]);
|
||||
|
||||
return result;
|
||||
@ -121,8 +116,7 @@ function createStakingInfo (bestNumber: BlockNumber, blockTime: number, sessionI
|
||||
...newDate(blocks, blockTime),
|
||||
blockNumber: bestNumber.add(blocks),
|
||||
blocks,
|
||||
info: eraIndex,
|
||||
type: 'stakingSlash'
|
||||
info: eraIndex
|
||||
};
|
||||
})
|
||||
: [];
|
||||
@ -132,15 +126,13 @@ function createStakingInfo (bestNumber: BlockNumber, blockTime: number, sessionI
|
||||
...newDate(blocksSes, blockTime),
|
||||
blockNumber: bestNumber.add(blocksSes),
|
||||
blocks: blocksSes,
|
||||
info: sessionInfo.currentIndex.add(BN_ONE),
|
||||
type: 'stakingEpoch'
|
||||
info: sessionInfo.currentIndex.add(BN_ONE)
|
||||
}]],
|
||||
['stakingEra', [{
|
||||
...newDate(blocksEra, blockTime),
|
||||
blockNumber: bestNumber.add(blocksEra),
|
||||
blocks: blocksEra,
|
||||
info: sessionInfo.activeEra.add(BN_ONE),
|
||||
type: 'stakingEra'
|
||||
info: sessionInfo.activeEra.add(BN_ONE)
|
||||
}]],
|
||||
['stakingSlash', slashEras]
|
||||
];
|
||||
@ -167,8 +159,7 @@ function createScheduled (bestNumber: BlockNumber, blockTime: number, scheduled:
|
||||
? idOrNull.isAscii
|
||||
? idOrNull.toUtf8()
|
||||
: idOrNull.toHex()
|
||||
: null,
|
||||
type: 'scheduler'
|
||||
: null
|
||||
});
|
||||
|
||||
return items;
|
||||
@ -176,10 +167,16 @@ function createScheduled (bestNumber: BlockNumber, blockTime: number, scheduled:
|
||||
}, [])]];
|
||||
}
|
||||
|
||||
function addFiltered (state: EntryInfo[], types: [EntryType, EntryInfo[]][]): EntryInfo[] {
|
||||
return types.reduce((state: EntryInfo[], [typeFilter, items]): EntryInfo[] =>
|
||||
state.filter(({ type }) => type !== typeFilter).concat(...items), state
|
||||
);
|
||||
function addFiltered (state: EntryInfoTyped[], types: [EntryType, EntryInfo[]][]): EntryInfoTyped[] {
|
||||
return types.reduce((state: EntryInfoTyped[], [typeFilter, items]): EntryInfoTyped[] => {
|
||||
return state
|
||||
.filter(({ type }) => type !== typeFilter)
|
||||
.concat(...items.map((item): EntryInfoTyped => {
|
||||
(item as EntryInfoTyped).type = typeFilter;
|
||||
|
||||
return item as EntryInfoTyped;
|
||||
}));
|
||||
}, state);
|
||||
}
|
||||
|
||||
// TODO council votes, tips closing
|
||||
@ -193,7 +190,7 @@ export default function useScheduled (): EntryInfo[] {
|
||||
const scheduled = useCall<ScheduleEntry[]>(api.query.scheduler?.agenda.entries);
|
||||
const sessionInfo = useCall<DeriveSessionProgress>(api.query.staking && api.derive.session?.progress);
|
||||
const slashes = useCall<SlashEntry[]>(api.query.staking?.unappliedSlashes.entries);
|
||||
const [state, setState] = useState<EntryInfo[]>([]);
|
||||
const [state, setState] = useState<EntryInfoTyped[]>([]);
|
||||
|
||||
useEffect((): void => {
|
||||
bestNumber && dispatches && setState((state) =>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user