react-use#useInterval TypeScript Examples
The following examples show how to use
react-use#useInterval.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: CountdownLabel.tsx From UUI with MIT License | 6 votes |
CountdownLabel = UUIFunctionComponent({
name: 'CountdownLabel',
nodes: {
Root: 'label',
},
propTypes: CountdownLabelPropTypes,
}, (props: CountdownLabelFeatureProps, { nodes }) => {
const { Root } = nodes
const finalProps = {
frequency: props.frequency || 1000,
format: props.format || 'hh:mm:ss',
allowNegative: props.allowNegative || false,
}
const generateLabelText = useCallback(() => {
const diff = differenceInMilliseconds(props.until, new Date())
const duration = (!props.allowNegative && diff && diff < 0)
? new Date(0)
: addMilliseconds(addHours(new Date(0), 16), diff)
return format(duration, finalProps.format)
}, [finalProps.format, props.allowNegative, props.until])
const [text, setText] = useState(generateLabelText())
useInterval(() => {
setText(generateLabelText())
}, finalProps.frequency)
return (
<Root>{text}</Root>
)
})
Example #2
Source File: BlockProvider.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 6 votes |
BlockProvider: FC = ({ children }) => {
const [blockNow, setBlockNow] = useState<State>({})
const { chainId, blockTime } = useNetwork()
const provider = useProvider()
const idle = useIsIdle()
const blockTimes = useBlockTimesForDates([date7d, date24h])
useInterval(() => {
if (!idle) {
// Only set the new block number when the user is active
// getBlockNumber apparently returns a string
provider?.getBlockNumber().then(latest => {
const value = latest ? parseInt(latest as unknown as string, 10) : undefined
setBlockNow({ ...blockNow, [chainId]: value })
})
}
}, blockTime)
const value = useMemo(() => {
return {
blockNow: blockNow[chainId],
block7d: blockTimes[0]?.number ? parseInt(blockTimes[0]?.number as unknown as string) : undefined,
block24h: blockTimes[1]?.number ? parseInt(blockTimes[1]?.number as unknown as string) : undefined,
}
}, [blockNow, blockTimes, chainId])
return <ctx.Provider value={value}>{children}</ctx.Provider>
}
Example #3
Source File: AutoSaveAndRestoreEmail.tsx From easy-email with MIT License | 5 votes |
export function AutoSaveAndRestoreEmail() {
const formState = useFormState<any>();
const { reset, mutators } = useForm();
const { id = 'new' } = useQuery<{ id: string }>();
const [currentEmail, setCurrentEmail] =
useLocalStorage<IEmailTemplate | null>(id, null);
const dirty = getIsFormTouched(formState.touched as any);
const [visible, setVisible] = useState(Boolean(currentEmail));
useEffect(() => {
if (dirty) {
setCurrentEmail(formState.values);
}
}, [dirty, formState.values, setCurrentEmail]);
useInterval(() => {
if (dirty) {
setCurrentEmail(formState.values);
}
}, 5000);
const onRestore = () => {
if (currentEmail) {
reset(currentEmail);
setCurrentEmail(null);
setVisible(false);
mutators.setFieldTouched(Object.keys(formState.touched || {})[0], true);
}
};
const onDiscard = () => {
setCurrentEmail(null);
setVisible(false);
};
const onBeforeConfirm = () => {
setCurrentEmail(null);
};
return (
<>
<Modal
title='Restore email?'
visible={Boolean(visible && currentEmail)}
onOk={onRestore}
okText='Restore'
cancelText='Discard'
onCancel={onDiscard}
style={{ zIndex: 10000 }}
>
<p>Are you want to restore unsaved email?</p>
</Modal>
<WarnAboutUnsavedChanges onBeforeConfirm={onBeforeConfirm} />
</>
);
}
Example #4
Source File: createRewardsEarnedContext.ts From mStable-apps with GNU Lesser General Public License v3.0 | 5 votes |
createRewardsEarnedContext = (): Readonly<[() => RewardsEarned, FC, Context<RewardsEarned>]> => {
const context = createContext<RewardsEarned>(null as never)
const RewardEarnedProvider: FC = ({ children }) => {
const stakedTokenQuery = useStakedTokenQuery()
const stakedTokenData = stakedTokenQuery.data?.stakedToken
const stakedToken = useTokenSubscription(stakedTokenData?.id)
const stakedTokenBalance = stakedToken?.balance
const [value, setValue] = useState<RewardsEarned>({ rewards: 0 })
useInterval(() => {
if (!(stakedTokenBalance && stakedTokenData?.stakingRewards && stakedTokenData.accounts?.[0])) {
return setValue({ rewards: 0 })
}
const {
stakingRewards: { lastUpdateTime, periodFinish, rewardPerTokenStored: _rewardPerTokenStored, rewardRate },
token: {
totalSupply: { bigDecimal: totalTokens },
},
accounts: [{ rewards: _rewards, rewardPerTokenPaid }],
} = stakedTokenData
// TODO as @client Apollo fields
const rewardPerTokenStored = BigNumber.from(_rewardPerTokenStored)
const rewards = BigNumber.from(_rewards)
const rewardPerToken = (() => {
if (totalTokens.exact.eq(0)) {
// If there is no StakingToken liquidity, avoid div(0)
return rewardPerTokenStored
}
const lastTimeRewardApplicable = Math.min(periodFinish, getUnixTime(Date.now()))
const timeSinceLastUpdate = lastTimeRewardApplicable - lastUpdateTime
// New reward units to distribute = rewardRate * timeSinceLastUpdate
const rewardUnitsToDistribute = BigNumber.from(rewardRate).mul(timeSinceLastUpdate)
// New reward units per token = (rewardUnitsToDistribute * 1e18) / totalTokens
const unitsToDistributePerToken = rewardUnitsToDistribute.mul(SCALE).div(totalTokens.exact)
return rewardPerTokenStored.add(unitsToDistributePerToken)
})()
// Current rate per token - rate user previously received
const userRewardDelta = rewardPerToken.sub(rewardPerTokenPaid)
if (userRewardDelta.eq(0)) {
return { rewards: new BigDecimal(rewards).simple, canClaim: rewards.gt(0) }
}
// New reward = staked tokens * difference in rate
const userNewReward = stakedTokenBalance.mulTruncate(userRewardDelta)
// Add to previous rewards
const summedRewards = rewards.add(userNewReward.exact)
return setValue({
canClaim: summedRewards.gt(0),
rewards: new BigDecimal(summedRewards).simple,
})
}, 5e3)
return providerFactory(context, { value }, children)
}
return [createUseContextFn(context), RewardEarnedProvider, context] as const
}
Example #5
Source File: NetworkProvider.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 5 votes |
NetworkPricesProvider: FC = ({ children }) => {
const network = useContext(networkCtx)
const [networkPrices, setNetworkPrices] = useFetchState<NetworkPrices>({})
const fetchPrices = useCallback(async () => {
if (!network) return
setNetworkPrices.fetching()
let gas: GasPrice
// eth mainnet
if (network.chainId === ChainIds.EthereumMainnet) {
const gasStationResponse = await fetch(network.gasStationEndpoint)
const gasRes: MyCryptoGas = await gasStationResponse.json()
gas = {
standard: gasRes.standard,
fast: gasRes.fast,
slow: gasRes.safeLow,
instant: gasRes.fastest,
}
// eth testnet
} else if ([ChainIds.EthereumGoerli, ChainIds.EthereumKovan, ChainIds.EthereumRopsten].includes(network.chainId)) {
// Testnets should use low gas
gas = {
standard: 3,
fast: 3,
slow: 3,
instant: 3,
}
// Matic Mainnet + Mumbai
} else {
const gasStationResponse = await fetch(network.gasStationEndpoint)
const gasRes: MaticMainGas = await gasStationResponse.json()
gas = {
standard: Math.min(30, gasRes.standard),
fast: Math.min(30, gasRes.fast),
slow: Math.min(30, gasRes.safeLow),
instant: Math.min(30, gasRes.fastest),
}
}
const priceResponse = await fetch(`https://api.coingecko.com/api/v3/simple/price?ids=${network.coingeckoId}&vs_currencies=usd`)
const priceResult: Record<typeof network['coingeckoId'], { usd: number }> = await priceResponse.json()
const nativeToken = priceResult[network.coingeckoId].usd
setNetworkPrices.value({ nativeToken, gas })
}, [network, setNetworkPrices])
useEffect(() => {
fetchPrices().catch(setNetworkPrices.error)
}, [fetchPrices, network, setNetworkPrices.error])
useInterval(() => {
fetchPrices().catch(setNetworkPrices.error)
}, 5 * 60 * 1000)
return <networkPricesCtx.Provider value={networkPrices}>{children}</networkPricesCtx.Provider>
}
Example #6
Source File: CountdownBar.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 5 votes |
CountdownBar: FC<Props> = ({ className, width = 150, percentage = 0, end, color, tip, textColor }) => {
const [value, setValue] = useState((percentage / 100) * width)
const endDate = new Date(end)
const dateDifference = differenceInSeconds(endDate, new Date())
const timeMultiplier = 60 // minute
const interval = ((((100 - percentage) / 100) * width) / dateDifference) * timeMultiplier
const renderer = ({ days: total, hours, minutes, completed }: CountdownRenderProps): ReactElement => {
const years = Math.floor(total / YEAR)
const months = Math.floor((total % YEAR) / MONTH)
const weeks = Math.floor((total % MONTH) / WEEK)
const days = total % 7
return (
<Time color={textColor}>
{completed
? `Complete`
: `${formatLabel(years, 'y')}
${formatLabel(months, 'm')}
${formatLabel(weeks, 'w')}
${formatLabel(days, 'd')}
${hours}h
${minutes}m`}
</Time>
)
}
useInterval(() => {
setValue(value - interval <= 0 ? 0 : value - interval)
}, 1000 * timeMultiplier)
return (
<Container className={className}>
<Progress style={{ width: `${width}px` }} color={color}>
<div style={{ width: `${value}px` }} />
</Progress>
<Countdown date={end} renderer={renderer} />
{tip && <StyledTooltip tip={tip} />}
</Container>
)
}
Example #7
Source File: import-export.tsx From erda-ui with GNU Affero General Public License v3.0 | 4 votes |
Record = ({ scope, scopeId, relationship, }: { scope: string; scopeId: string; relationship?: Custom_Dashboard.Relationship[]; }) => { const [data, loading] = getDashboardOperationRecord.useState(); const [hasError, setHasError] = React.useState(false); const [isFinished, setIsFinished] = React.useState(false); const [paging, setPaging] = React.useState({ pageNo: 1, pageSize: 10 }); const userMap = useUserMap(); const list = data?.histories || []; const total = data?.total; const getList = React.useCallback( (q?: { pageSize?: number; pageNo: number }) => { const { pageSize, pageNo } = q || {}; getDashboardOperationRecord .fetch({ scope, scopeId, pageSize: pageSize || paging.pageSize, pageNo: pageNo || paging.pageNo, }) .then((res) => { if (res.data?.histories.every((item) => ['Success', 'Failure'].includes(item.status))) { setIsFinished(true); } }) .catch(() => { setHasError(true); }); }, [paging?.pageSize, scope, scopeId], ); useInterval( () => { getList(); }, isFinished || hasError ? null : 5000, ); useMount(() => { getList({ pageNo: 1 }); }); const columns = [ { dataIndex: 'id', title: 'ID', render: (val: string) => <Tooltip title={val}>{val.slice(0, 8)}</Tooltip>, }, { dataIndex: 'type', title: i18n.t('Type'), render: (val: string, record: Custom_Dashboard.OperationHistory) => { const CMPTypeMap = { Import: i18n.t('Import'), Export: i18n.t('Export'), }; const MSPTypeMap = { Export: i18n.t('cmp:Export file'), Import: i18n.t('Import'), }; if (scope === CustomDashboardScope.ORG) { return CMPTypeMap[val]; } if (scope === CustomDashboardScope.MICRO_SERVICE) { const workspace = find(relationship, (item) => item.tenantId === record.targetScopeId)?.workspace; if (record.targetScopeId && workspace) { const exportEnv = workSpaceMap[workspace].label; return `${i18n.t('cmp:Export to')}${exportEnv}`; } return MSPTypeMap[val]; } return '-'; }, }, { dataIndex: 'operatorId', title: i18n.t('Operator'), render: (val: string) => { const cU = userMap[Number(val)]; if (val && cU) { return ( <span> <Avatar size="small" src={cU.avatar}> {cU.nick ? getAvatarChars(cU.nick) : i18n.t('None')} </Avatar> <span className="ml-0.5 mr-1" title={cU.name}> {cU.nick || cU.name || val || i18n.t('None')} </span> </span> ); } return '-'; }, }, { dataIndex: 'createdAt', title: i18n.t('Time'), render: (val: string) => (val ? moment(val).format('YYYY/MM/DD HH:mm:ss') : '-'), }, { dataIndex: 'status', title: i18n.t('cmp:Status'), render: (val: string, record: IMPORT_EXPORT_FILE_LIST.FileRecord) => { const statusMap = { Failure: { text: i18n.t('failed'), status: 'error', tip: record.errorInfo, }, Success: { text: i18n.t('succeed'), status: 'success', }, Processing: { text: i18n.t('In Progress'), status: 'processing', }, }; return statusMap[val] ? <Badge {...statusMap[val]} showDot={false} /> : '-'; }, }, ]; const actions = { render: (record: Custom_Dashboard.OperationHistory) => { const { download, viewResult } = { download: { title: i18n.t('Download'), onClick: () => { downloadApi.fetch({ uuid: record.fileUuid, $options: { isDownload: true, }, }); }, }, viewResult: { title: i18n.t('View Results'), onClick: () => { if (record.status === 'Success') { Modal.success({ title: i18n.t('View Results'), content: ( <span className="font-medium text-base text-default text-success"> {record.type === 'Import' ? i18n.t('imported successfully') : i18n.t('exported successfully')}! </span> ), }); } if (record.status === 'Failure') { Modal.error({ title: i18n.t('View Results'), content: <span className="font-medium text-base text-default">{record.errorMessage}</span>, }); } if (record.status === 'Processing') { Modal.info({ title: i18n.t('View Results'), content: i18n.t('no results yet'), }); } }, }, }; return record.fileUuid ? [download, viewResult] : [viewResult]; }, }; return ( <ErdaTable rowKey="id" loading={loading} columns={columns} wrapperClassName="h-full" actions={actions} dataSource={list} pagination={{ ...paging, current: paging.pageNo || 1, total }} onChange={(pageInfo) => { setPaging({ ...pageInfo, pageNo: pageInfo.current }); getList({ pageNo: pageInfo.current || 1, pageSize: pageInfo.pageSize }); }} /> ); }
Example #8
Source File: operation-project-record.tsx From erda-ui with GNU Affero General Public License v3.0 | 4 votes |
OperationProjectRecords = ({ visible, setVisible, isClickExport, setIsClickExport }: IProps) => {
const orgID = orgStore.getState((s) => s.currentOrg.id);
const [handleProjectRecord, handleRecordLoading] = importExportFileRecord.useState();
const userMap = useUserMap();
const [activeKey, setActiveKey] = React.useState('all');
const [hasError, setHasError] = React.useState(false);
const [isFinished, setIsFinished] = React.useState(false);
const [searchObj, setSearchObj] = React.useState<IState>({
pageNo: 1,
pageSize: 10,
query: '',
asc: false,
});
const getImportExportProjectRecord = React.useCallback(() => {
importExportFileRecord
.fetch({
...searchObj,
orgID,
types: handleFileTypeMap[activeKey],
projectName: searchObj.query,
pageNo: searchObj.pageNo,
pageSize: searchObj.pageSize,
})
.then((res) => {
if (res.data?.list.every((item) => ['success', 'fail'].includes(item.state))) {
setIsFinished(true);
}
if (res.data?.list.some((item) => !['success', 'fail'].includes(item.state))) {
setIsFinished(false);
}
})
.catch(() => {
setHasError(true);
});
}, [activeKey, orgID, searchObj]);
useMount(() => {
getImportExportProjectRecord();
});
const getColumnOrder = (key?: string) => {
if (key) {
return searchObj.orderBy === key ? (searchObj.asc ? 'ascend' : 'descend') : undefined;
}
return undefined;
};
useInterval(
() => {
getImportExportProjectRecord();
},
isFinished || hasError ? null : 5000,
);
React.useEffect(() => getImportExportProjectRecord(), [activeKey, getImportExportProjectRecord, orgID, searchObj]);
React.useEffect(() => {
if (isClickExport) {
setActiveKey('export');
}
}, [isClickExport]);
const recordColumns = [
{
title: i18n.t('project'),
dataIndex: 'projectDisplayName',
ellipsis: {
showTitle: false,
},
},
{
title: i18n.t('Status'),
dataIndex: 'state',
ellipsis: {
showTitle: false,
},
render: (state: string) => <Badge status={stateMap[state].state} text={stateMap[state].text} />,
},
{
title: i18n.t('Type'),
dataIndex: 'type',
ellipsis: {
showTitle: false,
},
render: (type: string) => {
if (type === handleFileTypeMap.import) {
return i18n.t('Import');
}
return i18n.t('Export');
},
},
{
title: i18n.t('Operator'),
dataIndex: 'operatorID',
ellipsis: {
showTitle: false,
},
render: (text: string) => {
const { avatar, nick } = userMap[text];
return (
<>
<Avatar src={avatar || undefined} size="small" className="flex-shrink-0">
{nick ? getAvatarChars(nick) : i18n.t('None')}
</Avatar>
<span> {nick}</span>
</>
);
},
},
{
title: i18n.t('execution time'),
dataIndex: 'updatedAt',
ellipsis: {
showTitle: false,
},
sorter: true,
sortOrder: getColumnOrder('updatedAt'),
render: (updatedAt: string) => moment(updatedAt).format('YYYY-MM-DD HH:mm:ss'),
},
];
const ErrorContent = ({ record }: { record: IMPORT_EXPORT_FILE_LIST.FileRecord }) => {
const results = record.description.match(/\d+/g) || [];
const errorInfo = record.errorInfo.split('\n').filter((item) => item !== ')');
return (
<>
{/* it will return two numbers, first one is successful number, other is failed */}
{results.length === 2 && (
<div className="font-medium">
{i18n.t('{success} apps imported successfully, {fail} apps imported failed', {
success: results[0],
fail: results[1],
})}
</div>
)}
{map(errorInfo, (item, index) => (
<div key={index} className="mt-2 text-sm text-default-6 text-justify">
{index + 1}. {item}
</div>
))}
</>
);
};
const recordActions: IActions<IMPORT_EXPORT_FILE_LIST.FileRecord> = {
width: 120,
render: (record: IMPORT_EXPORT_FILE_LIST.FileRecord) => {
const { viewResult, exportProject } = {
viewResult: {
title: i18n.t('View Results'),
onClick: () => {
if (record.state === 'success') {
Modal.success({
title: i18n.t('View Results'),
content: (
<span className="font-medium text-base text-default text-success">
{record.type === 'projectTemplateImport'
? i18n.t('imported successfully')
: i18n.t('exported successfully')}
!
</span>
),
});
}
if (record.state === 'fail') {
Modal.error({
title: i18n.t('View Results'),
content: <ErrorContent record={record} />,
});
}
if (record.state === 'pending' || record.state === 'processing') {
Modal.info({
title: i18n.t('View Results'),
content: i18n.t('no results yet'),
});
}
},
},
exportProject: {
title: i18n.t('Download'),
onClick: () => window.open(`/api/files/${record.apiFileUUID}`),
},
};
return record.type === handleFileTypeMap.import ? [viewResult] : [viewResult, exportProject];
},
};
const onSearch = (query: string) => {
setSearchObj((prev) => ({ ...prev, query, pageNo: 1 }));
};
const handleTableChange = (pagination: { current: number; pageSize: number }, filters: any, sorter: any) => {
setSearchObj((prev) => ({
...prev,
pageNo: pagination.current,
pageSize: pagination.pageSize,
orderBy: sorter?.field && sorter?.order ? sorter.field : undefined,
asc: sorter?.order ? sorter.order === 'ascend' : undefined,
}));
};
return (
<>
<Drawer
width="80%"
onClose={() => {
setVisible(false);
setActiveKey('all');
setIsClickExport(false);
}}
visible={visible}
destroyOnClose
title={i18n.t('Import/Export Records')}
className="dice-drawer"
>
<RadioTabs
options={options}
value={activeKey}
onChange={(v) => {
setActiveKey(v as string);
setSearchObj({ ...searchObj, pageNo: 1 });
}}
className="mb-2"
/>
<Spin spinning={handleRecordLoading}>
<Table
rowKey="id"
columns={recordColumns}
dataSource={handleProjectRecord?.list}
actions={recordActions}
slot={
<Filter
config={[
{
type: Input,
name: 'projectName',
customProps: {
placeholder: i18n.t('Search by project name'),
style: { width: 200 },
},
},
]}
onFilter={({ projectName }: { projectName: string }) => onSearch(projectName)}
/>
}
pagination={{
current: searchObj.pageNo,
pageSize: searchObj.pageSize,
total: handleProjectRecord?.total,
showSizeChanger: true,
pageSizeOptions: PAGINATION.pageSizeOptions,
}}
onChange={handleTableChange}
/>
</Spin>
</Drawer>
</>
);
}
Example #9
Source File: import-export.tsx From erda-ui with GNU Affero General Public License v3.0 | 4 votes |
Record = ({ testSetId, setShowRefresh }: { testSetId: number; setShowRefresh: (b: boolean) => void }) => {
const [hasError, setHasError] = React.useState(false);
const [isFinished, setIsFinished] = React.useState(false);
const loginUser = userStore.useStore((s) => s.loginUser);
const [list, setList] = React.useState<TEST_CASE.ImportExportRecordItem[]>([]);
const [counter, setCounter] = React.useState<TEST_CASE.ImportExportCounter>({});
const { getImportExportRecords } = testCaseStore.effects;
const [loading] = useLoading(testCaseStore, ['getImportExportRecords']);
const userMap = useUserMap();
const getData = (firstTime = false) => {
const query = {
types: ['import', 'export'],
};
getImportExportRecords(query)
.then((result: TEST_CASE.ImportExportResult) => {
if (result?.list.every((item) => ['success', 'fail'].includes(item.state))) {
setIsFinished(true);
}
if (!isEmpty(result)) {
if (!firstTime) {
let haveJustFinishedJob = false;
const myProcessingJob: Record<string, boolean> = {};
list.forEach((item) => {
if (item.operatorID === loginUser.id && ['processing', 'pending'].includes(item.state)) {
myProcessingJob[item.id] = true;
}
});
let haveJustSuccessJob = false;
result?.list.forEach((item) => {
if (
item.operatorID === loginUser.id &&
['success', 'fail'].includes(item.state) &&
myProcessingJob[item.id]
) {
haveJustFinishedJob = true;
}
// new result state is success and not existing in list cache, means it's newly import record
const previousItem = list.find((origin) => origin.id === item.id);
if (
item.state === 'success' &&
item.testSetID === testSetId &&
(!previousItem || previousItem.state !== 'success')
) {
haveJustSuccessJob = true;
}
});
if (haveJustFinishedJob) {
message.info(
i18n.t('dop:The import and export tasks you submitted have status updates, please check the records'),
4,
);
}
if (haveJustSuccessJob) {
setShowRefresh(true);
setList(result?.list);
}
}
setList(result?.list);
setCounter(result?.counter);
}
})
.catch(() => {
setHasError(true);
});
};
useMount(() => {
getData(true);
});
useInterval(
() => {
getData(false);
},
isFinished || hasError ? null : 5000,
);
let badgeCount = 0;
list.forEach((item) => {
if (['pending', 'processing'].includes(item.state)) {
badgeCount += 1;
}
});
const columns = [
{
dataIndex: 'id',
title: 'ID',
},
{
dataIndex: 'type',
title: i18n.t('Type'),
render: (val: string) => {
const typeMap = {
import: i18n.t('Import'),
export: i18n.t('Export'),
};
return typeMap[val] || '-';
},
},
{
dataIndex: 'operatorID',
title: i18n.t('Operator'),
render: (val: string) => {
const cU = userMap[val];
return (
<span>
<Avatar size="small" src={cU?.avatar}>
{cU.nick ? getAvatarChars(cU.nick) : i18n.t('None')}
</Avatar>
<span className="ml-0.5 mr-1" title={cU.name}>
{cU.nick || cU.name || val || i18n.t('common:None')}
</span>
</span>
);
},
},
{
dataIndex: 'createdAt',
title: i18n.t('Time'),
render: (val: string) => (val ? moment(val).format('YYYY/MM/DD HH:mm:ss') : '-'),
},
{
dataIndex: 'state',
title: i18n.t('Status'),
render: (val: string) => {
const statusMap = {
fail: {
text: i18n.t('failed'),
status: 'error',
},
success: {
text: i18n.t('succeed'),
status: 'success',
},
pending: {
text: i18n.t('waiting'),
status: 'warning',
},
processing: {
text: i18n.t('In Progress'),
status: 'processing',
},
};
return statusMap[val] ? <Badge {...statusMap[val]} showDot={false} /> : '-';
},
},
{
title: i18n.t('Description'),
dataIndex: 'description',
key: 'description',
},
];
const actions = {
render: (record: TEST_CASE.ImportExportRecordItem) => {
return record.apiFileUUID && ['success', 'fail'].includes(record.state)
? [
{
title: i18n.t('Download'),
onClick: () => {
window.open(`/api/files/${record.apiFileUUID}`);
},
},
]
: [];
},
};
return (
<ErdaTable
rowKey="id"
loading={loading}
columns={columns}
wrapperClassName="h-full"
actions={actions}
onReload={() => getData(false)}
dataSource={list}
/>
);
}
Example #10
Source File: TorrentPeers.tsx From flood with GNU General Public License v3.0 | 4 votes |
TorrentPeers: FC = () => {
const [peers, setPeers] = useState<Array<TorrentPeer>>([]);
const [pollingDelay, setPollingDelay] = useState<number | null>(null);
const fetchPeers = () => {
setPollingDelay(null);
if (UIStore.activeModal?.id === 'torrent-details') {
TorrentActions.fetchTorrentPeers(UIStore.activeModal?.hash).then((data) => {
if (data != null) {
setPeers(data);
}
});
}
setPollingDelay(ConfigStore.pollInterval);
};
useEffect(() => fetchPeers(), []);
useInterval(() => fetchPeers(), pollingDelay);
return (
<div className="torrent-details__section torrent-details__section--peers">
<table
className="torrent-details__table table"
css={{
td: {
maxWidth: '140px',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
},
}}
>
<thead className="torrent-details__table__heading">
<tr>
<th className="torrent-details__table__heading--primary">
<Trans id="torrents.details.peers" />
<Badge>{peers.length}</Badge>
</th>
<th className="torrent-details__table__heading--secondary">DL</th>
<th className="torrent-details__table__heading--secondary">UL</th>
<th className="torrent-details__table__heading--secondary">%</th>
<th className="torrent-details__table__heading--secondary">Client</th>
<th className="torrent-details__table__heading--secondary">Enc</th>
<th className="torrent-details__table__heading--secondary">In</th>
</tr>
</thead>
<tbody>
{peers.map((peer) => {
const {country: countryCode} = peer;
const encryptedIcon = peer.isEncrypted ? <Lock /> : null;
const incomingIcon = peer.isIncoming ? <CheckmarkThick /> : null;
return (
<tr key={peer.address}>
<td>
<span className="peers-list__flag">
<Suspense fallback={<Spinner />}>
<CountryFlag countryCode={countryCode} />
</Suspense>
<span className="peers-list__flag__text">{countryCode}</span>
</span>
{peer.address}
</td>
<td>
<Size value={peer.downloadRate} isSpeed />
</td>
<td>
<Size value={peer.uploadRate} isSpeed />
</td>
<td>{`${Math.ceil(peer.completedPercent)}%`}</td>
<td>{peer.clientVersion}</td>
<td className="peers-list__encryption">{encryptedIcon}</td>
<td className="peers-list__incoming">{incomingIcon}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
Example #11
Source File: RewardStreamsProvider.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 4 votes |
RewardStreamsProvider: FC<{
refreshInterval?: number
vault?: BoostedVaultState
}> = ({ children, refreshInterval = 15e3, vault }) => {
const [currentTime, setCurrentTime] = useState<number>(nowUnix)
const account = useAccount()
const signer = useSigner()
const [claimRange, setClaimRange] = useState<[number, number] | undefined>(undefined)
const vaultContract = useRef<BoostedVault>()
useEffect(() => {
if (!signer || !account || !vault) return
if (!vaultContract.current) {
vaultContract.current = BoostedVault__factory.connect(vault.address, signer)
}
vaultContract.current
.unclaimedRewards(account)
.catch(error => {
console.error(error)
})
.then(result => {
if (result) {
const { first, last } = result
setClaimRange([first.toNumber(), last.toNumber()])
} else {
setClaimRange([0, 0])
}
})
}, [signer, vault, account, setClaimRange])
useInterval(() => {
setCurrentTime(getUnixTime(Date.now()))
}, refreshInterval)
const rewardStreams = useMemo(() => {
if (vault?.account) {
const {
lockupDuration,
account: { rewardEntries, lastClaim, lastAction },
account,
} = vault
const [unlockedStreams, lockedStreams] = rewardEntries
// Remove fully claimed entries
.filter(entry => (lastClaim ? entry.finish > lastClaim : true))
// Split entries based on start/finish and now;
// this helps to visualise it
.reduce<[RewardEntry[], RewardEntry[]]>(
([_unlocked, _locked], entry) => {
const { start, finish, index } = entry
if (start <= currentTime && finish >= currentTime) {
// Unlocked portion and locked portion
return [
[
..._unlocked,
{
...entry,
start,
finish: currentTime,
index,
},
],
[
..._locked,
{
...entry,
start: currentTime,
finish,
},
],
]
}
if (start <= currentTime) {
// Unlocked
return [[..._unlocked, entry], _locked]
}
// Locked
return [_unlocked, [..._locked, entry]]
},
[[], []],
)
.map<Stream[]>(entries =>
entries.map(entry => {
const { start, finish, index } = entry
const amount = getEntryAmount(entry)
const type = start >= currentTime ? StreamType.Locked : StreamType.Unlocked
return {
amount: { [type]: amount },
start,
finish,
index,
}
}),
)
const unlocked = unlockedStreams.reduce((prev, stream) => prev + (stream.amount[StreamType.Unlocked] ?? 0), 0)
const locked = lockedStreams.reduce((prev, stream) => prev + (stream.amount[StreamType.Locked] ?? 0), 0)
const earned = calculateEarned(currentTime, vault)
const earnedStream: Stream = {
amount: {
[StreamType.Earned]: earned.unlocked,
},
start: lastClaim > 0 ? Math.min(lastClaim, lastAction) : lastAction,
finish: currentTime,
index: 0,
}
const previewLocked = earned.locked ?? 0
const previewStream: Stream = {
amount: {
[StreamType.LockedPreview]: previewLocked,
},
start: lastAction + lockupDuration,
finish: currentTime + lockupDuration,
}
const total = earned.unlocked + previewLocked + locked + unlocked
// TODO Unclaimed and earned can overlap (but not immediately)
// amount: {
// [StreamType.Unclaimed]: unclaimed,
// [StreamType.Earned]: earned.total,
// [StreamType.Unlocked]: unlocked,
// },
// start: unlockedStreams[0]?.start
// ? Math.min(earnedStream.start, unlockedStreams[0].start)
// : earnedStream.start,
// finish: currentTime,
const chartData: ChartData = [earnedStream, ...unlockedStreams, ...lockedStreams, previewStream]
.filter(stream => stream.start > 0)
.flatMap(({ start, finish, amount }) => [
{
...ZERO_AMOUNTS,
t: start,
},
{
...ZERO_AMOUNTS,
...amount,
t: finish,
},
{
...ZERO_AMOUNTS,
t: finish + 1,
},
])
if (!claimRange) {
return
}
const platform = parseInt((account?.platformRewards ?? 0).toString()) / 1e18
const amounts = {
earned,
locked,
previewLocked,
unlocked,
total,
platform,
}
return {
amounts,
chartData,
claimRange: claimRange,
currentTime,
nextUnlock: lockedStreams[0]?.start,
previewStream,
lockedStreams: [...lockedStreams, previewStream],
} as RewardStreams
}
}, [currentTime, vault, claimRange])
return <ctx.Provider value={rewardStreams}>{children}</ctx.Provider>
}
Example #12
Source File: createRewardsEarnedContext.ts From mStable-apps with GNU Lesser General Public License v3.0 | 4 votes |
createRewardsEarnedContext = (
stakingRewardsCtx: Context<StakingRewardsExtended>,
): Readonly<[() => RewardsEarned, FC, Context<RewardsEarned>]> => {
const context = createContext<RewardsEarned>(null as never)
const RewardEarnedProvider: FC = ({ children }) => {
const stakingRewards = useContext(stakingRewardsCtx)
const [value, setValue] = useState<RewardsEarned>({ rewards: [] })
useInterval(() => {
if (!stakingRewards.stakingRewardsContract) {
return setValue({ rewards: [] })
}
const {
lastUpdateTime,
periodFinish,
platformRewards: { platformReward, platformRewardPerTokenStoredNow, platformRewardRate, platformToken } = {},
rewardPerTokenStoredNow,
rewardRate,
rewardsToken,
stakingBalance,
stakingReward,
totalSupply,
} = stakingRewards.stakingRewardsContract
const totalTokens = totalSupply.exact
const rewardPerToken = (() => {
if (totalTokens.eq(0)) {
// If there is no StakingToken liquidity, avoid div(0)
return { rewardPerTokenStoredNow, platformRewardPerTokenStoredNow }
}
const lastTimeRewardApplicable = Math.min(periodFinish, getUnixTime(Date.now()))
const timeSinceLastUpdate = lastTimeRewardApplicable - lastUpdateTime
// New reward units to distribute = rewardRate * timeSinceLastUpdate
const rewardUnitsToDistribute = rewardRate.exact.mul(timeSinceLastUpdate)
const platformRewardUnitsToDistribute = platformRewardRate?.exact.mul(timeSinceLastUpdate)
// New reward units per token = (rewardUnitsToDistribute * 1e18) / totalTokens
const unitsToDistributePerToken = rewardUnitsToDistribute.mul(SCALE).div(totalTokens)
const platformUnitsToDistributePerToken = platformRewardUnitsToDistribute?.mul(SCALE).div(totalTokens)
return {
rewardPerTokenStoredNow: rewardPerTokenStoredNow.add(unitsToDistributePerToken),
platformRewardPerTokenStoredNow: platformRewardPerTokenStoredNow?.add(platformUnitsToDistributePerToken ?? BigDecimal.ZERO),
}
})()
// Current rate per token - rate user previously received
const userRewardDelta = rewardPerToken.rewardPerTokenStoredNow.sub(stakingReward.amountPerTokenPaid).exact
const platformUserRewardDelta = rewardPerToken.platformRewardPerTokenStoredNow?.sub(
platformReward?.amountPerTokenPaid ?? BigDecimal.ZERO,
)
// New reward = staked tokens * difference in rate
const userNewReward = stakingBalance.mulTruncate(userRewardDelta)
const userNewPlatformReward = platformUserRewardDelta ? stakingBalance.mulTruncate(platformUserRewardDelta.exact) : undefined
// Add to previous rewards
const summedRewards = stakingReward.amount.add(userNewReward)
const summedPlatformRewards =
userNewPlatformReward && platformReward ? platformReward.amount.add(userNewPlatformReward) : BigDecimal.ZERO
return setValue({
canClaim: summedRewards.exact.gt(0) || summedPlatformRewards.exact.gt(0),
rewards: [
{
earned: summedRewards,
token: rewardsToken.symbol,
},
...(platformToken
? [
{
earned: summedPlatformRewards,
token: platformToken.symbol,
},
]
: []),
],
})
}, 1e3)
return providerFactory(context, { value }, children)
}
return [createUseContextFn(context), RewardEarnedProvider, context] as const
}
Example #13
Source File: index.tsx From Search-Next with GNU General Public License v3.0 | 4 votes |
Weather: FC<WeatherProps> = (props) => {
const {
setting = {} as IndexPageWeatherSetting,
weather: localWeatherData = {} as SaveWeatherData,
className,
} = props;
const { interval = 15 } = setting;
const { city, weather, key, pluginKey, latlng } = localWeatherData ?? {};
const [pluginLoading, setPluginLoading] = useState(false);
const [qweatherPlugin, setQweatherPlugin] = useState<HTMLElement>();
const [qweatherNow, setQweatherNow] = useState<QWeatherNow>();
const [open, setOpen] = useState(false);
const NoMaxWidthTooltip = styled(({ className, ...props }: TooltipProps) => (
<Tooltip {...props} classes={{ popper: className }} />
))({
[`& .${tooltipClasses.tooltip}`]: {
maxWidth: 'none',
width: '450px',
height: '150px',
padding: '0',
},
});
const initQweatherPlugin = () => {
// @ts-ignore
window.WIDGET = {
CONFIG: {
layout: '1',
width: '450',
height: '150',
background: '1',
dataColor: 'FFFFFF',
key: pluginKey,
},
};
const hePluginStandardEleBox = document.createElement('div');
const hePluginStandardEle = document.createElement('div');
hePluginStandardEleBox.id = 'he-plugin-standard-box';
hePluginStandardEle.id = 'he-plugin-standard';
hePluginStandardEleBox.style.display = 'none';
hePluginStandardEleBox.appendChild(hePluginStandardEle);
const boxInHtml = document.getElementById('he-plugin-standard-box');
boxInHtml && document.body.removeChild(boxInHtml);
document.body.appendChild(hePluginStandardEleBox);
const script = document.createElement('script');
script.src =
'https://widget.qweather.net/standard/static/js/he-standard-common.js?v=2.0';
script.id = 'qweather-widget-script';
script.onload = () => {
setPluginLoading(false);
// ! 修改和风天气插件 去掉切换城市按钮
const timer = setInterval(() => {
const pluginLocationEle = document.querySelector('.wv-lt-location');
if (pluginLocationEle && pluginLocationEle.children.length == 2) {
const eleChildren = pluginLocationEle.children;
const cityNameEle = eleChildren[0];
// @ts-ignore
if (cityNameEle.title) {
const divCityName = document.createElement('div');
// @ts-ignore
divCityName.innerHTML = cityNameEle.title;
// @ts-ignore
divCityName.style.color = cityNameEle.style.color;
divCityName.style.fontSize = '16px';
// ? 这里删除两次 0,每次删除后,数组都会变化
pluginLocationEle.removeChild(eleChildren[0]);
pluginLocationEle.removeChild(eleChildren[0]);
pluginLocationEle.appendChild(divCityName);
clearInterval(timer);
}
}
}, 100);
};
const inHtml = document.getElementById('qweather-widget-script');
inHtml && document.body.removeChild(inHtml);
document.body.appendChild(script);
};
// 获取天气信息
// const getWeatherInfo = (params: QweatherNowParams) => {
// setLoading(true);
// const { key } = params;
// qweatherNow(params).then((res) => {
// setWeather(key ? res : res.data);
// setLoading(false);
// });
// };
useEffect(() => {
initQweatherPlugin();
}, []);
useEffect(() => {
if (weather) setQweatherNow(weather);
}, [weather]);
useInterval(() => {}, interval * 60 * 1000);
useEffect(() => {
if (open) {
initQweatherPlugin();
const hePluginStandardEleBox = document.getElementById(
'he-plugin-standard-box',
);
if (hePluginStandardEleBox) {
document.body.removeChild(hePluginStandardEleBox);
hePluginStandardEleBox.style.display = 'block';
setQweatherPlugin(hePluginStandardEleBox);
}
} else {
setQweatherPlugin(undefined);
setPluginLoading(true);
}
}, [open]);
if (!qweatherNow) return <div></div>;
return (
<div
className="h-10 flex items-center"
onMouseEnter={() => {
pluginKey && setOpen(true);
}}
onMouseLeave={() => {
pluginKey && setOpen(false);
}}
>
<NoMaxWidthTooltip
open={open}
title={
<Loading loading={pluginLoading} color="#fff" full>
<div
dangerouslySetInnerHTML={{
__html: qweatherPlugin?.innerHTML ?? '',
}}
></div>
</Loading>
}
>
<div
className={cx(
className,
'flex items-center px-2 gap-2 mx-2',
pluginKey && 'cursor-pointer',
)}
>
{<SvgIcon name={qweatherNow.now?.icon + '-fill'} />}
<div className="flex gap-1 font-semibold">
<span>{qweatherNow.now?.temp}</span>
<span>℃</span>
</div>
</div>
</NoMaxWidthTooltip>
</div>
);
}