mirror of
https://github.com/mastodon/mastodon.git
synced 2026-05-05 12:58:05 -05:00
Some checks failed
Check i18n / check-i18n (push) Waiting to run
Chromatic / Run Chromatic (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (ruby) (push) Waiting to run
Check formatting / lint (push) Waiting to run
CSS Linting / lint (push) Waiting to run
JavaScript Linting / lint (push) Waiting to run
Ruby Linting / lint (push) Waiting to run
JavaScript Testing / test (push) Waiting to run
Historical data migration test / test (14-alpine) (push) Waiting to run
Historical data migration test / test (15-alpine) (push) Waiting to run
Historical data migration test / test (16-alpine) (push) Waiting to run
Historical data migration test / test (17-alpine) (push) Waiting to run
Ruby Testing / build (production) (push) Waiting to run
Ruby Testing / build (test) (push) Waiting to run
Ruby Testing / test (.ruby-version) (push) Blocked by required conditions
Ruby Testing / test (3.2) (push) Blocked by required conditions
Ruby Testing / test (3.3) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (.ruby-version) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.2) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.3) (push) Blocked by required conditions
Ruby Testing / End to End testing (.ruby-version) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.2) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.3) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:8.10.2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, opensearchproject/opensearch:2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.2, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.3, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Bundler Audit / security (push) Has been cancelled
Haml Linting / lint (push) Has been cancelled
94 lines
2.1 KiB
TypeScript
94 lines
2.1 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
|
|
import { useIntl } from 'react-intl';
|
|
import type { IntlShape } from 'react-intl';
|
|
|
|
import { dismissAlert } from 'mastodon/actions/alerts';
|
|
import type {
|
|
Alert as AlertType,
|
|
TranslatableString,
|
|
TranslatableValues,
|
|
} from 'mastodon/models/alert';
|
|
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
|
|
|
import { Alert } from './alert';
|
|
|
|
const formatIfNeeded = (
|
|
intl: IntlShape,
|
|
message: TranslatableString,
|
|
values?: TranslatableValues,
|
|
) => {
|
|
if (typeof message === 'object') {
|
|
return intl.formatMessage(message, values);
|
|
}
|
|
|
|
return message;
|
|
};
|
|
|
|
const TimedAlert: React.FC<{
|
|
alert: AlertType;
|
|
dismissAfter: number;
|
|
}> = ({
|
|
alert: { key, title, message, values, action, onClick },
|
|
dismissAfter,
|
|
}) => {
|
|
const dispatch = useAppDispatch();
|
|
const intl = useIntl();
|
|
const [active, setActive] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const setActiveTimeout = setTimeout(() => {
|
|
setActive(true);
|
|
}, 1);
|
|
|
|
return () => {
|
|
clearTimeout(setActiveTimeout);
|
|
};
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const dismissTimeout = setTimeout(() => {
|
|
setActive(false);
|
|
|
|
// Allow CSS transition to finish before removing from the DOM
|
|
setTimeout(() => {
|
|
dispatch(dismissAlert({ key }));
|
|
}, 500);
|
|
}, dismissAfter);
|
|
|
|
return () => {
|
|
clearTimeout(dismissTimeout);
|
|
};
|
|
}, [dispatch, setActive, key, dismissAfter]);
|
|
|
|
return (
|
|
<Alert
|
|
isActive={active}
|
|
title={title ? formatIfNeeded(intl, title, values) : undefined}
|
|
message={formatIfNeeded(intl, message, values)}
|
|
action={action ? formatIfNeeded(intl, action, values) : undefined}
|
|
onActionClick={onClick}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export const AlertsController: React.FC = () => {
|
|
const alerts = useAppSelector((state) => state.alerts);
|
|
|
|
if (alerts.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div className='notification-list'>
|
|
{alerts.map((alert, idx) => (
|
|
<TimedAlert
|
|
key={alert.key}
|
|
alert={alert}
|
|
dismissAfter={5000 + idx * 1000}
|
|
/>
|
|
))}
|
|
</div>
|
|
);
|
|
};
|