diff --git a/packages/page-calendar/src/DayItem.tsx b/packages/page-calendar/src/DayItem.tsx index 99ad8a84ba..b2923ea43a 100644 --- a/packages/page-calendar/src/DayItem.tsx +++ b/packages/page-calendar/src/DayItem.tsx @@ -3,9 +3,11 @@ import type { EntryInfo } from './types'; -import React, { useMemo } from 'react'; +import React, { useMemo, useState, useCallback } from 'react'; import styled from 'styled-components'; import { formatNumber, isString } from '@polkadot/util'; +import { dateCalendarFormat } from './util'; +import { Button } from '@polkadot/react-components'; import { useTranslation } from './translate'; @@ -22,6 +24,41 @@ function assertUnreachable (x: never): never { function DayItem ({ className, item: { date, info, type } }: Props): React.ReactElement { const { t } = useTranslation(); + const [description, setDescription] = useState(''); + + 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); + }, + [description, date] + ); + const desc = useMemo( (): React.ReactNode => { const id: string | null = info && ( @@ -46,54 +83,70 @@ function DayItem ({ className, item: { date, info, type } }: Props): React.React : ['treasurySpend'].includes(type) ?
{t('via Treasury')}
: undefined; + let s = ''; switch (type) { case 'councilElection': - return <>
{t('Election of new council candidates')}
{typeLink}; + s = t('Election of new council candidates'); + break; case 'councilMotion': - return <>
{t('Voting ends on council motion {{id}}', { replace: { id } })}
{typeLink}; + s = t('Voting ends on council motion {{id}}', { replace: { id } }); + break; case 'democracyDispatch': - return <>
{t('Enactment of the result of referendum {{id}}', { replace: { id } })}
{typeLink}; + s = t('Enactment of the result of referendum {{id}}', { replace: { id } }); + break; case 'democracyLaunch': - return <>
{t('Start of the next referendum voting period')}
{typeLink}; + s = t('Start of the next referendum voting period'); + break; case 'referendumDispatch': - return <>
{t('Potential dispatch of referendum {{id}} (if passed)', { replace: { id } })}
{typeLink}; + s = t('Potential dispatch of referendum {{id}} (if passed)', { replace: { id } }); + break; case 'referendumVote': - return <>
{t('Voting ends for referendum {{id}}', { replace: { id } })}
{typeLink}; + s = t('Voting ends for referendum {{id}}', { replace: { id } }); + break; case 'scheduler': - return <>
{ - id - ? t('Execute named scheduled task {{id}}', { replace: { id } }) - : t('Execute anonymous scheduled task') - }
{typeLink}; + s = id + ? t('Execute named scheduled task {{id}}', { replace: { id } }) + : t('Execute anonymous scheduled task'); + break; case 'stakingEpoch': - return <>
{t('Start of a new staking session {{id}}', { replace: { id } })}
{typeLink}; + s = t('Start of a new staking session {{id}}', { replace: { id } }); + break; case 'stakingEra': - return <>
{t('Start of a new staking era {{id}}', { replace: { id } })}
{typeLink}; + s = t('Start of a new staking era {{id}}', { replace: { id } }); + break; case 'stakingSlash': - return <>
{t('Application of slashes from era {{id}}', { replace: { id } })}
{typeLink}; + s = t('Application of slashes from era {{id}}', { replace: { id } }); + break; case 'treasurySpend': - return <>
{t('Start of next spending period')}
{typeLink}; + s = t('Start of next spending period'); + break; case 'societyChallenge': - return <>
{t('Start of next membership challenge period')}
{typeLink}; + s = t('Start of next membership challenge period'); + break; case 'societyRotate': - return <>
{t('Acceptance of new members and bids')}
{typeLink}; + s = t('Acceptance of new members and bids'); + break; default: return assertUnreachable(type); } + + setDescription(s); + + return (<>
{s}
{typeLink}); }, [info, t, type] ); @@ -102,6 +155,13 @@ function DayItem ({ className, item: { date, info, type } }: Props): React.React
{date.toLocaleTimeString().split(':').slice(0, 2).join(':')}
{desc} + {date && ( +
); } @@ -116,6 +176,17 @@ export default React.memo(styled(DayItem)` margin-left: 0.5rem; } + .exportCal { + padding: 0; + position: absolute; + right: 1.5rem; + + .ui--Icon { + width: 0.7rem; + height: 0.7rem; + } + } + .itemTime { background: #999; padding: 0 0.375rem; diff --git a/packages/page-calendar/src/util.ts b/packages/page-calendar/src/util.ts index b582c055a1..1a941d1c96 100644 --- a/packages/page-calendar/src/util.ts +++ b/packages/page-calendar/src/util.ts @@ -54,3 +54,11 @@ export function getDateState (_dateMonth: Date, _dateSelected: Date): DateState startClass: `start${DAYS[dateMonth.getDay()]}` }; } + +export function dateCalendarFormat (date: Date): string { + return new Date(date) + .toISOString() + .split('.')[0] + .replaceAll('-', '') + .replaceAll(':', '') + 'Z'; +}