diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d7d9ffcf..356e6f08d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Profile: add RSS link to user profiles. - Posts: fix posts filtering. - Chats: reset chat message field height after sending a message. +- Admin: allow to manage announcements. ### Changed - Chats: improved display of media attachments. diff --git a/app/soapbox/actions/admin.ts b/app/soapbox/actions/admin.ts index e24999aa1..52be03ac2 100644 --- a/app/soapbox/actions/admin.ts +++ b/app/soapbox/actions/admin.ts @@ -1,13 +1,18 @@ +import { defineMessages } from 'react-intl'; + import { fetchRelationships } from 'soapbox/actions/accounts'; import { importFetchedAccount, importFetchedAccounts, importFetchedStatuses } from 'soapbox/actions/importer'; +import toast from 'soapbox/toast'; import { filterBadges, getTagDiff } from 'soapbox/utils/badges'; import { getFeatures } from 'soapbox/utils/features'; import api, { getLinks } from '../api'; +import { openModal } from './modals'; + import type { AxiosResponse } from 'axios'; import type { AppDispatch, RootState } from 'soapbox/store'; -import type { APIEntity } from 'soapbox/types/entities'; +import type { APIEntity, Announcement } from 'soapbox/types/entities'; const ADMIN_CONFIG_FETCH_REQUEST = 'ADMIN_CONFIG_FETCH_REQUEST'; const ADMIN_CONFIG_FETCH_SUCCESS = 'ADMIN_CONFIG_FETCH_SUCCESS'; @@ -77,16 +82,45 @@ const ADMIN_USERS_UNSUGGEST_REQUEST = 'ADMIN_USERS_UNSUGGEST_REQUEST'; const ADMIN_USERS_UNSUGGEST_SUCCESS = 'ADMIN_USERS_UNSUGGEST_SUCCESS'; const ADMIN_USERS_UNSUGGEST_FAIL = 'ADMIN_USERS_UNSUGGEST_FAIL'; -const ADMIN_USER_INDEX_EXPAND_FAIL = 'ADMIN_USER_INDEX_EXPAND_FAIL'; +const ADMIN_USER_INDEX_EXPAND_FAIL = 'ADMIN_USER_INDEX_EXPAND_FAIL'; const ADMIN_USER_INDEX_EXPAND_REQUEST = 'ADMIN_USER_INDEX_EXPAND_REQUEST'; const ADMIN_USER_INDEX_EXPAND_SUCCESS = 'ADMIN_USER_INDEX_EXPAND_SUCCESS'; -const ADMIN_USER_INDEX_FETCH_FAIL = 'ADMIN_USER_INDEX_FETCH_FAIL'; +const ADMIN_USER_INDEX_FETCH_FAIL = 'ADMIN_USER_INDEX_FETCH_FAIL'; const ADMIN_USER_INDEX_FETCH_REQUEST = 'ADMIN_USER_INDEX_FETCH_REQUEST'; const ADMIN_USER_INDEX_FETCH_SUCCESS = 'ADMIN_USER_INDEX_FETCH_SUCCESS'; const ADMIN_USER_INDEX_QUERY_SET = 'ADMIN_USER_INDEX_QUERY_SET'; +const ADMIN_ANNOUNCEMENTS_FETCH_FAIL = 'ADMIN_ANNOUNCEMENTS_FETCH_FAILS'; +const ADMIN_ANNOUNCEMENTS_FETCH_REQUEST = 'ADMIN_ANNOUNCEMENTS_FETCH_REQUEST'; +const ADMIN_ANNOUNCEMENTS_FETCH_SUCCESS = 'ADMIN_ANNOUNCEMENTS_FETCH_SUCCESS'; + +const ADMIN_ANNOUNCEMENTS_EXPAND_FAIL = 'ADMIN_ANNOUNCEMENTS_EXPAND_FAILS'; +const ADMIN_ANNOUNCEMENTS_EXPAND_REQUEST = 'ADMIN_ANNOUNCEMENTS_EXPAND_REQUEST'; +const ADMIN_ANNOUNCEMENTS_EXPAND_SUCCESS = 'ADMIN_ANNOUNCEMENTS_EXPAND_SUCCESS'; + +const ADMIN_ANNOUNCEMENT_CHANGE_CONTENT = 'ADMIN_ANNOUNCEMENT_CHANGE_CONTENT'; +const ADMIN_ANNOUNCEMENT_CHANGE_START_TIME = 'ADMIN_ANNOUNCEMENT_CHANGE_START_TIME'; +const ADMIN_ANNOUNCEMENT_CHANGE_END_TIME = 'ADMIN_ANNOUNCEMENT_CHANGE_END_TIME'; +const ADMIN_ANNOUNCEMENT_CHANGE_ALL_DAY = 'ADMIN_ANNOUNCEMENT_CHANGE_ALL_DAY'; + +const ADMIN_ANNOUNCEMENT_CREATE_REQUEST = 'ADMIN_ANNOUNCEMENT_CREATE_REQUEST'; +const ADMIN_ANNOUNCEMENT_CREATE_SUCCESS = 'ADMIN_ANNOUNCEMENT_CREATE_REQUEST'; +const ADMIN_ANNOUNCEMENT_CREATE_FAIL = 'ADMIN_ANNOUNCEMENT_CREATE_FAIL'; + +const ADMIN_ANNOUNCEMENT_DELETE_REQUEST = 'ADMIN_ANNOUNCEMENT_DELETE_REQUEST'; +const ADMIN_ANNOUNCEMENT_DELETE_SUCCESS = 'ADMIN_ANNOUNCEMENT_DELETE_REQUEST'; +const ADMIN_ANNOUNCEMENT_DELETE_FAIL = 'ADMIN_ANNOUNCEMENT_DELETE_FAIL'; + +const ADMIN_ANNOUNCEMENT_MODAL_INIT = 'ADMIN_ANNOUNCEMENT_MODAL_INIT'; + +const messages = defineMessages({ + announcementCreateSuccess: { id: 'admin.edit_announcement.created', defaultMessage: 'Announcement created' }, + announcementDeleteSuccess: { id: 'admin.edit_announcement.deleted', defaultMessage: 'Announcement deleted' }, + announcementUpdateSuccess: { id: 'admin.edit_announcement.updated', defaultMessage: 'Announcement edited' }, +}); + const nicknamesFromIds = (getState: () => RootState, ids: string[]) => ids.map(id => getState().accounts.get(id)!.acct); const fetchConfig = () => @@ -598,6 +632,93 @@ const expandUserIndex = () => }); }; +const fetchAdminAnnouncements = () => + (dispatch: AppDispatch, getState: () => RootState) => { + dispatch({ type: ADMIN_ANNOUNCEMENTS_FETCH_REQUEST }); + return api(getState) + .get('/api/pleroma/admin/announcements', { params: { limit: 50 } }) + .then(({ data }) => { + dispatch({ type: ADMIN_ANNOUNCEMENTS_FETCH_SUCCESS, announcements: data }); + return data; + }).catch(error => { + dispatch({ type: ADMIN_ANNOUNCEMENTS_FETCH_FAIL, error }); + }); + }; + +const expandAdminAnnouncements = () => + (dispatch: AppDispatch, getState: () => RootState) => { + const page = getState().admin_announcements.page; + + dispatch({ type: ADMIN_ANNOUNCEMENTS_EXPAND_REQUEST }); + return api(getState) + .get('/api/pleroma/admin/announcements', { params: { limit: 50, offset: page * 50 } }) + .then(({ data }) => { + dispatch({ type: ADMIN_ANNOUNCEMENTS_EXPAND_SUCCESS, announcements: data }); + return data; + }).catch(error => { + dispatch({ type: ADMIN_ANNOUNCEMENTS_EXPAND_FAIL, error }); + }); + }; + +const changeAnnouncementContent = (content: string) => ({ + type: ADMIN_ANNOUNCEMENT_CHANGE_CONTENT, + value: content, +}); + +const changeAnnouncementStartTime = (time: Date | null) => ({ + type: ADMIN_ANNOUNCEMENT_CHANGE_START_TIME, + value: time, +}); + +const changeAnnouncementEndTime = (time: Date | null) => ({ + type: ADMIN_ANNOUNCEMENT_CHANGE_END_TIME, + value: time, +}); + +const changeAnnouncementAllDay = (allDay: boolean) => ({ + type: ADMIN_ANNOUNCEMENT_CHANGE_ALL_DAY, + value: allDay, +}); + +const handleCreateAnnouncement = () => + (dispatch: AppDispatch, getState: () => RootState) => { + dispatch({ type: ADMIN_ANNOUNCEMENT_CREATE_REQUEST }); + + const { id, content, starts_at, ends_at, all_day } = getState().admin_announcements.form; + + return api(getState)[id ? 'patch' : 'post']( + id ? `/api/pleroma/admin/announcements/${id}` : '/api/pleroma/admin/announcements', + { content, starts_at, ends_at, all_day }, + ).then(({ data }) => { + dispatch({ type: ADMIN_ANNOUNCEMENT_CREATE_SUCCESS, announcement: data }); + toast.success(id ? messages.announcementUpdateSuccess : messages.announcementCreateSuccess); + dispatch(fetchAdminAnnouncements()); + return data; + }).catch(error => { + dispatch({ type: ADMIN_ANNOUNCEMENT_CREATE_FAIL, error }); + }); + }; + +const deleteAnnouncement = (id: string) => + (dispatch: AppDispatch, getState: () => RootState) => { + dispatch({ type: ADMIN_ANNOUNCEMENT_DELETE_REQUEST, id }); + + return api(getState).delete(`/api/pleroma/admin/announcements/${id}`).then(({ data }) => { + dispatch({ type: ADMIN_ANNOUNCEMENT_DELETE_SUCCESS, id }); + toast.success(messages.announcementDeleteSuccess); + dispatch(fetchAdminAnnouncements()); + return data; + }).catch(error => { + dispatch({ type: ADMIN_ANNOUNCEMENT_DELETE_FAIL, id, error }); + }); + }; + +const initAnnouncementModal = (announcement?: Announcement) => + (dispatch: AppDispatch) => { + dispatch({ type: ADMIN_ANNOUNCEMENT_MODAL_INIT, announcement }); + dispatch(openModal('EDIT_ANNOUNCEMENT')); + }; + export { ADMIN_CONFIG_FETCH_REQUEST, ADMIN_CONFIG_FETCH_SUCCESS, @@ -657,6 +778,23 @@ export { ADMIN_USER_INDEX_FETCH_REQUEST, ADMIN_USER_INDEX_FETCH_SUCCESS, ADMIN_USER_INDEX_QUERY_SET, + ADMIN_ANNOUNCEMENTS_FETCH_FAIL, + ADMIN_ANNOUNCEMENTS_FETCH_REQUEST, + ADMIN_ANNOUNCEMENTS_FETCH_SUCCESS, + ADMIN_ANNOUNCEMENTS_EXPAND_FAIL, + ADMIN_ANNOUNCEMENTS_EXPAND_REQUEST, + ADMIN_ANNOUNCEMENTS_EXPAND_SUCCESS, + ADMIN_ANNOUNCEMENT_CHANGE_CONTENT, + ADMIN_ANNOUNCEMENT_CHANGE_START_TIME, + ADMIN_ANNOUNCEMENT_CHANGE_END_TIME, + ADMIN_ANNOUNCEMENT_CHANGE_ALL_DAY, + ADMIN_ANNOUNCEMENT_CREATE_FAIL, + ADMIN_ANNOUNCEMENT_CREATE_REQUEST, + ADMIN_ANNOUNCEMENT_CREATE_SUCCESS, + ADMIN_ANNOUNCEMENT_DELETE_FAIL, + ADMIN_ANNOUNCEMENT_DELETE_REQUEST, + ADMIN_ANNOUNCEMENT_DELETE_SUCCESS, + ADMIN_ANNOUNCEMENT_MODAL_INIT, fetchConfig, updateConfig, updateSoapboxConfig, @@ -686,4 +824,13 @@ export { setUserIndexQuery, fetchUserIndex, expandUserIndex, + fetchAdminAnnouncements, + expandAdminAnnouncements, + changeAnnouncementContent, + changeAnnouncementStartTime, + changeAnnouncementEndTime, + changeAnnouncementAllDay, + handleCreateAnnouncement, + deleteAnnouncement, + initAnnouncementModal, }; diff --git a/app/soapbox/features/admin/announcements.tsx b/app/soapbox/features/admin/announcements.tsx new file mode 100644 index 000000000..c4ab66571 --- /dev/null +++ b/app/soapbox/features/admin/announcements.tsx @@ -0,0 +1,128 @@ +import React, { useEffect } from 'react'; +import { FormattedDate, FormattedMessage, defineMessages, useIntl } from 'react-intl'; + +import { deleteAnnouncement, fetchAdminAnnouncements, initAnnouncementModal } from 'soapbox/actions/admin'; +import { openModal } from 'soapbox/actions/modals'; +import ScrollableList from 'soapbox/components/scrollable-list'; +import { Button, Column, HStack, Stack, Text } from 'soapbox/components/ui'; +import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; +import { Announcement as AnnouncementEntity } from 'soapbox/types/entities'; + +const messages = defineMessages({ + heading: { id: 'column.admin.announcements', defaultMessage: 'Announcements' }, + deleteConfirm: { id: 'confirmations.admin.delete_announcement.confirm', defaultMessage: 'Delete' }, + deleteHeading: { id: 'confirmations.admin.delete_announcement.heading', defaultMessage: 'Delete announcement' }, + deleteMessage: { id: 'confirmations.admin.delete_announcement.message', defaultMessage: 'Are you sure you want to delete the announcement?' }, +}); + +interface IAnnouncement { + announcement: AnnouncementEntity +} + +const Announcement: React.FC = ({ announcement }) => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + + const handleEditAnnouncement = (announcement: AnnouncementEntity) => () => { + dispatch(initAnnouncementModal(announcement)); + }; + + const handleDeleteAnnouncement = (id: string) => () => { + dispatch(openModal('CONFIRM', { + heading: intl.formatMessage(messages.deleteHeading), + message: intl.formatMessage(messages.deleteMessage), + confirm: intl.formatMessage(messages.deleteConfirm), + onConfirm: () => dispatch(deleteAnnouncement(id)), + })); + }; + + return ( +
+ + + {(announcement.starts_at || announcement.ends_at || announcement.all_day) && ( + + {announcement.starts_at && ( + + + + + {' '} + + + )} + {announcement.ends_at && ( + + + + + {' '} + + + )} + {announcement.all_day && ( + + + + )} + + )} + + + + + +
+ ); +}; + +const Announcements: React.FC = () => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + + const announcements = useAppSelector((state) => state.admin_announcements.items); + const isLoading = useAppSelector((state) => state.admin_announcements.isLoading); + + useEffect(() => { + dispatch(fetchAdminAnnouncements()); + }, []); + + const handleCreateAnnouncement = () => { + dispatch(initAnnouncementModal()); + }; + + const emptyMessage = ; + + return ( + + + + + {announcements.map((announcement) => ( + + ))} + + + + ); +}; + +export default Announcements; diff --git a/app/soapbox/features/admin/tabs/dashboard.tsx b/app/soapbox/features/admin/tabs/dashboard.tsx index 035feb3c8..f57740dfe 100644 --- a/app/soapbox/features/admin/tabs/dashboard.tsx +++ b/app/soapbox/features/admin/tabs/dashboard.tsx @@ -43,6 +43,7 @@ const Dashboard: React.FC = () => { const navigateToSoapboxConfig = () => history.push('/soapbox/config'); const navigateToModerationLog = () => history.push('/soapbox/admin/log'); + const navigateToAnnouncements = () => history.push('/soapbox/admin/announcements'); const v = parseVersion(instance.version); @@ -95,6 +96,13 @@ const Dashboard: React.FC = () => { onClick={navigateToModerationLog} label={} /> + + {features.announcements && ( + } + /> + )} {account.admin && ( diff --git a/app/soapbox/features/chats/components/chat-textarea.tsx b/app/soapbox/features/chats/components/chat-textarea.tsx index 3304bc40a..2b491ed69 100644 --- a/app/soapbox/features/chats/components/chat-textarea.tsx +++ b/app/soapbox/features/chats/components/chat-textarea.tsx @@ -67,4 +67,4 @@ const ChatTextarea: React.FC = ({ ); }; -export default ChatTextarea; \ No newline at end of file +export default ChatTextarea; diff --git a/app/soapbox/features/ui/components/modal-root.tsx b/app/soapbox/features/ui/components/modal-root.tsx index f787af840..dc4801c29 100644 --- a/app/soapbox/features/ui/components/modal-root.tsx +++ b/app/soapbox/features/ui/components/modal-root.tsx @@ -2,41 +2,42 @@ import React from 'react'; import Base from 'soapbox/components/modal-root'; import { - MediaModal, - VideoModal, - BoostModal, - ConfirmationModal, - MuteModal, - ReportModal, - EmbedModal, - CryptoDonateModal, - ListEditor, - ListAdder, - MissingDescriptionModal, - ActionsModal, - HotkeysModal, - ComposeModal, - ReplyMentionsModal, - UnauthorizedModal, - EditFederationModal, - ComponentModal, - ReactionsModal, - FavouritesModal, - ReblogsModal, - MentionsModal, - LandingPageModal, - BirthdaysModal, - AccountNoteModal, - CompareHistoryModal, - VerifySmsModal, - FamiliarFollowersModal, - ComposeEventModal, - JoinEventModal, AccountModerationModal, + AccountNoteModal, + ActionsModal, + BirthdaysModal, + BoostModal, + CompareHistoryModal, + ComponentModal, + ComposeEventModal, + ComposeModal, + ConfirmationModal, + CryptoDonateModal, + EditAnnouncementModal, + EditFederationModal, + EmbedModal, EventMapModal, EventParticipantsModal, - PolicyModal, + FamiliarFollowersModal, + FavouritesModal, + HotkeysModal, + JoinEventModal, + LandingPageModal, + ListAdder, + ListEditor, ManageGroupModal, + MediaModal, + MentionsModal, + MissingDescriptionModal, + MuteModal, + PolicyModal, + ReactionsModal, + ReblogsModal, + ReplyMentionsModal, + ReportModal, + UnauthorizedModal, + VerifySmsModal, + VideoModal, } from 'soapbox/features/ui/util/async-components'; import BundleContainer from '../containers/bundle-container'; @@ -45,42 +46,44 @@ import { BundleProps } from './bundle'; import BundleModalError from './bundle-modal-error'; import ModalLoading from './modal-loading'; +/* eslint sort-keys: "error" */ const MODAL_COMPONENTS = { - 'MEDIA': MediaModal, - 'VIDEO': VideoModal, - 'BOOST': BoostModal, - 'CONFIRM': ConfirmationModal, - 'MISSING_DESCRIPTION': MissingDescriptionModal, - 'MUTE': MuteModal, - 'REPORT': ReportModal, - 'ACTIONS': ActionsModal, - 'EMBED': EmbedModal, - 'LIST_EDITOR': ListEditor, - 'LIST_ADDER': ListAdder, - 'HOTKEYS': HotkeysModal, - 'COMPOSE': ComposeModal, - 'REPLY_MENTIONS': ReplyMentionsModal, - 'UNAUTHORIZED': UnauthorizedModal, - 'CRYPTO_DONATE': CryptoDonateModal, - 'EDIT_FEDERATION': EditFederationModal, - 'COMPONENT': ComponentModal, - 'REBLOGS': ReblogsModal, - 'FAVOURITES': FavouritesModal, - 'REACTIONS': ReactionsModal, - 'MENTIONS': MentionsModal, - 'LANDING_PAGE': LandingPageModal, - 'BIRTHDAYS': BirthdaysModal, - 'ACCOUNT_NOTE': AccountNoteModal, - 'COMPARE_HISTORY': CompareHistoryModal, - 'VERIFY_SMS': VerifySmsModal, - 'FAMILIAR_FOLLOWERS': FamiliarFollowersModal, - 'COMPOSE_EVENT': ComposeEventModal, - 'JOIN_EVENT': JoinEventModal, 'ACCOUNT_MODERATION': AccountModerationModal, + 'ACCOUNT_NOTE': AccountNoteModal, + 'ACTIONS': ActionsModal, + 'BIRTHDAYS': BirthdaysModal, + 'BOOST': BoostModal, + 'COMPARE_HISTORY': CompareHistoryModal, + 'COMPONENT': ComponentModal, + 'COMPOSE': ComposeModal, + 'COMPOSE_EVENT': ComposeEventModal, + 'CONFIRM': ConfirmationModal, + 'CRYPTO_DONATE': CryptoDonateModal, + 'EDIT_ANNOUNCEMENT': EditAnnouncementModal, + 'EDIT_FEDERATION': EditFederationModal, + 'EMBED': EmbedModal, 'EVENT_MAP': EventMapModal, 'EVENT_PARTICIPANTS': EventParticipantsModal, - 'POLICY': PolicyModal, + 'FAMILIAR_FOLLOWERS': FamiliarFollowersModal, + 'FAVOURITES': FavouritesModal, + 'HOTKEYS': HotkeysModal, + 'JOIN_EVENT': JoinEventModal, + 'LANDING_PAGE': LandingPageModal, + 'LIST_ADDER': ListAdder, + 'LIST_EDITOR': ListEditor, 'MANAGE_GROUP': ManageGroupModal, + 'MEDIA': MediaModal, + 'MENTIONS': MentionsModal, + 'MISSING_DESCRIPTION': MissingDescriptionModal, + 'MUTE': MuteModal, + 'POLICY': PolicyModal, + 'REACTIONS': ReactionsModal, + 'REBLOGS': ReblogsModal, + 'REPLY_MENTIONS': ReplyMentionsModal, + 'REPORT': ReportModal, + 'UNAUTHORIZED': UnauthorizedModal, + 'VERIFY_SMS': VerifySmsModal, + 'VIDEO': VideoModal, }; export type ModalType = keyof typeof MODAL_COMPONENTS | null; diff --git a/app/soapbox/features/ui/components/modals/edit-announcement-modal.tsx b/app/soapbox/features/ui/components/modals/edit-announcement-modal.tsx new file mode 100644 index 000000000..ad1fcb647 --- /dev/null +++ b/app/soapbox/features/ui/components/modals/edit-announcement-modal.tsx @@ -0,0 +1,119 @@ +import React from 'react'; +import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; + +import { changeAnnouncementAllDay, changeAnnouncementContent, changeAnnouncementEndTime, changeAnnouncementStartTime, handleCreateAnnouncement } from 'soapbox/actions/admin'; +import { closeModal } from 'soapbox/actions/modals'; +import { Form, FormGroup, HStack, Modal, Stack, Text, Textarea, Toggle } from 'soapbox/components/ui'; +import BundleContainer from 'soapbox/features/ui/containers/bundle-container'; +import { DatePicker } from 'soapbox/features/ui/util/async-components'; +import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; + +const messages = defineMessages({ + save: { id: 'admin.edit_announcement.save', defaultMessage: 'Save' }, + announcementContentPlaceholder: { id: 'admin.edit_announcement.fields.content_placeholder', defaultMessage: 'Announcement content' }, + announcementStartTimePlaceholder: { id: 'admin.edit_announcement.fields.start_time_placeholder', defaultMessage: 'Announcement starts on…' }, + announcementEndTimePlaceholder: { id: 'admin.edit_announcement.fields.end_time_placeholder', defaultMessage: 'Announcement ends on…' }, +}); + +interface IEditAnnouncementModal { + onClose: (type?: string) => void, +} + +const EditAnnouncementModal: React.FC = ({ onClose }) => { + const dispatch = useAppDispatch(); + const intl = useIntl(); + + const id = useAppSelector((state) => state.admin_announcements.form.id); + const content = useAppSelector((state) => state.admin_announcements.form.content); + const startTime = useAppSelector((state) => state.admin_announcements.form.starts_at); + const endTime = useAppSelector((state) => state.admin_announcements.form.ends_at); + const allDay = useAppSelector((state) => state.admin_announcements.form.all_day); + + const onChangeContent: React.ChangeEventHandler = ({ target }) => + dispatch(changeAnnouncementContent(target.value)); + + const onChangeStartTime = (date: Date | null) => dispatch(changeAnnouncementStartTime(date)); + + const onChangeEndTime = (date: Date | null) => dispatch(changeAnnouncementEndTime(date)); + + const onChangeAllDay: React.ChangeEventHandler = ({ target }) => dispatch(changeAnnouncementAllDay(target.checked)); + + const onClickClose = () => { + onClose('EDIT_ANNOUNCEMENT'); + }; + + const handleSubmit = () => dispatch(handleCreateAnnouncement()).then(() => dispatch(closeModal('EDIT_ANNOUNCEMENT'))); + + return ( + + : } + confirmationAction={handleSubmit} + confirmationText={intl.formatMessage(messages.save)} + > +
+ } + > +