From 3ad5df805e22ddd473fdaa9a92df335a61fad7fc Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 9 Feb 2022 15:04:53 -0500 Subject: Add delete status confirm modal --- src/modules/config.js | 6 ++++++ src/modules/instance.js | 6 ++++++ 2 files changed, 12 insertions(+) (limited to 'src/modules') diff --git a/src/modules/config.js b/src/modules/config.js index 3cd6888f..a8949030 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -78,6 +78,12 @@ export const defaultState = { minimalScopesMode: undefined, // instance default // This hides statuses filtered via a word filter hideFilteredStatuses: undefined, // instance default + modalOnRepeat: undefined, // instance default + modalOnUnfollow: undefined, // instance default + modalOnBlock: undefined, // instance default + modalOnMute: undefined, // instance default + modalOnDelete: undefined, // instance default + modalOnLogout: undefined, // instance default playVideosInModal: false, useOneClickNsfw: false, useContainFit: true, diff --git a/src/modules/instance.js b/src/modules/instance.js index 8e8d13d3..6fc3830c 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -71,6 +71,12 @@ const defaultState = { hideSitename: false, hideUserStats: false, muteBotStatuses: false, + modalOnRepeat: false, + modalOnUnfollow: false, + modalOnBlock: true, + modalOnMute: false, + modalOnDelete: true, + modalOnLogout: true, loginMethod: 'password', logo: '/static/logo.svg', logoMargin: '.2em', -- cgit v1.2.3-70-g09d2 From 228a9afdf5ecc10a17de31f88bd88ad1efbe0004 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 30 Apr 2022 11:08:19 -0400 Subject: Add timed-mute functionality --- src/components/poll/poll_form.js | 13 ++----------- src/components/user_card/user_card.js | 13 +++++++++++-- src/components/user_card/user_card.scss | 5 +++++ src/components/user_card/user_card.vue | 28 +++++++++++++++++++++++++++- src/modules/users.js | 7 +++++-- src/services/api/api.service.js | 8 ++++++-- src/services/date_utils/date_utils.js | 16 ++++++++++++++++ 7 files changed, 72 insertions(+), 18 deletions(-) (limited to 'src/modules') diff --git a/src/components/poll/poll_form.js b/src/components/poll/poll_form.js index e30645c3..a2070155 100644 --- a/src/components/poll/poll_form.js +++ b/src/components/poll/poll_form.js @@ -94,19 +94,10 @@ export default { }, convertExpiryToUnit (unit, amount) { // Note: we want seconds and not milliseconds - switch (unit) { - case 'minutes': return (1000 * amount) / DateUtils.MINUTE - case 'hours': return (1000 * amount) / DateUtils.HOUR - case 'days': return (1000 * amount) / DateUtils.DAY - } + return DateUtils.secondsToUnit(unit, amount) }, convertExpiryFromUnit (unit, amount) { - // Note: we want seconds and not milliseconds - switch (unit) { - case 'minutes': return 0.001 * amount * DateUtils.MINUTE - case 'hours': return 0.001 * amount * DateUtils.HOUR - case 'days': return 0.001 * amount * DateUtils.DAY - } + return DateUtils.unitToSeconds(unit, amount) }, expiryAmountChange () { this.expiryAmount = diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index 1bcc4341..e17bf8eb 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -1,3 +1,4 @@ +import { unitToSeconds } from 'src/services/date_utils/date_utils.js' import UserAvatar from '../user_avatar/user_avatar.vue' import RemoteFollow from '../remote_follow/remote_follow.vue' import ProgressButton from '../progress_button/progress_button.vue' @@ -48,7 +49,9 @@ export default { return { followRequestInProgress: false, betterShadow: this.$store.state.interface.browserSupport.cssFilter, - showingConfirmMute: false + showingConfirmMute: false, + muteExpiryAmount: 0, + muteExpiryUnit: 'minutes' } }, created () { @@ -142,6 +145,9 @@ export default { shouldConfirmMute () { return this.mergedConfig.modalOnMute }, + muteExpiryUnits () { + return ['minutes', 'hours', 'days'] + }, ...mapGetters(['mergedConfig']) }, components: { @@ -172,7 +178,10 @@ export default { } }, doMuteUser () { - this.$store.dispatch('muteUser', this.user.id) + this.$store.dispatch('muteUser', { + id: this.user.id, + expiresIn: this.shouldConfirmMute ? unitToSeconds(this.muteExpiryUnit, this.muteExpiryAmount) : 0 + }) this.hideConfirmMute() }, unmuteUser () { diff --git a/src/components/user_card/user_card.scss b/src/components/user_card/user_card.scss index d56b6672..4ab93a8a 100644 --- a/src/components/user_card/user_card.scss +++ b/src/components/user_card/user_card.scss @@ -355,3 +355,8 @@ text-decoration: none; } } + +.mute-expiry { + display: flex; + flex-direction: row; +} diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index 01882aa8..2de14063 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -325,7 +325,7 @@ > +
+ + + +
diff --git a/src/modules/users.js b/src/modules/users.js index 053e44b6..a1316ba2 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -61,13 +61,16 @@ const editUserNote = (store, { id, comment }) => { .then((relationship) => store.commit('updateUserRelationship', [relationship])) } -const muteUser = (store, id) => { +const muteUser = (store, args) => { + const id = typeof args === 'object' ? args.id : args + const expiresIn = typeof args === 'object' ? args.expiresIn : 0 + const predictedRelationship = store.state.relationships[id] || { id } predictedRelationship.muting = true store.commit('updateUserRelationship', [predictedRelationship]) store.commit('addMuteId', id) - return store.rootState.api.backendInteractor.muteUser({ id }) + return store.rootState.api.backendInteractor.muteUser({ id, expiresIn }) .then((relationship) => { store.commit('updateUserRelationship', [relationship]) store.commit('addMuteId', id) diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index af12265e..c7a36af9 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -1118,8 +1118,12 @@ const fetchMutes = ({ credentials }) => { .then((users) => users.map(parseUser)) } -const muteUser = ({ id, credentials }) => { - return promisedRequest({ url: MASTODON_MUTE_USER_URL(id), credentials, method: 'POST' }) +const muteUser = ({ id, expiresIn, credentials }) => { + const payload = {} + if (expiresIn) { + payload['expires_in'] = expiresIn + } + return promisedRequest({ url: MASTODON_MUTE_USER_URL(id), credentials, method: 'POST', payload }) } const unmuteUser = ({ id, credentials }) => { diff --git a/src/services/date_utils/date_utils.js b/src/services/date_utils/date_utils.js index c93d2176..ed8e1417 100644 --- a/src/services/date_utils/date_utils.js +++ b/src/services/date_utils/date_utils.js @@ -41,3 +41,19 @@ export const relativeTimeShort = (date, nowThreshold = 1) => { r.key += '_short' return r } + +export const unitToSeconds = (unit, amount) => { + switch (unit) { + case 'minutes': return 0.001 * amount * MINUTE + case 'hours': return 0.001 * amount * HOUR + case 'days': return 0.001 * amount * DAY + } +} + +export const secondsToUnit = (unit, amount) => { + switch (unit) { + case 'minutes': return (1000 * amount) / MINUTE + case 'hours': return (1000 * amount) / HOUR + case 'days': return (1000 * amount) / DAY + } +} -- cgit v1.2.3-70-g09d2 From 547e85c7c6f9bf8779cc06344c4eebaaa8f9d775 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 7 Jun 2022 12:37:16 -0400 Subject: Add confirm dialogs for accept & deny follow requests --- .../follow_request_card/follow_request_card.js | 49 +++++++++++++++++++++- .../follow_request_card/follow_request_card.vue | 22 ++++++++++ src/components/notification/notification.js | 43 ++++++++++++++++++- src/components/notification/notification.vue | 22 ++++++++++ src/components/settings_modal/tabs/general_tab.vue | 10 +++++ src/modules/config.js | 2 + src/modules/instance.js | 2 + 7 files changed, 147 insertions(+), 3 deletions(-) (limited to 'src/modules') diff --git a/src/components/follow_request_card/follow_request_card.js b/src/components/follow_request_card/follow_request_card.js index cbd75311..b0873bb1 100644 --- a/src/components/follow_request_card/follow_request_card.js +++ b/src/components/follow_request_card/follow_request_card.js @@ -1,10 +1,18 @@ import BasicUserCard from '../basic_user_card/basic_user_card.vue' +import ConfirmModal from '../confirm_modal/confirm_modal.vue' import { notificationsFromStore } from '../../services/notification_utils/notification_utils.js' const FollowRequestCard = { props: ['user'], components: { - BasicUserCard + BasicUserCard, + ConfirmModal + }, + data () { + return { + showingApproveConfirmDialog: false, + showingDenyConfirmDialog: false + } }, methods: { findFollowRequestNotificationId () { @@ -13,7 +21,26 @@ const FollowRequestCard = { ) return notif && notif.id }, + showApproveConfirmDialog () { + this.showingApproveConfirmDialog = true + }, + hideApproveConfirmDialog () { + this.showingApproveConfirmDialog = false + }, + showDenyConfirmDialog () { + this.showingDenyConfirmDialog = true + }, + hideDenyConfirmDialog () { + this.showingDenyConfirmDialog = false + }, approveUser () { + if (this.shouldConfirmApprove) { + this.showApproveConfirmDialog() + } else { + this.doApprove() + } + }, + doApprove () { this.$store.state.api.backendInteractor.approveUser({ id: this.user.id }) this.$store.dispatch('removeFollowRequest', this.user) @@ -25,14 +52,34 @@ const FollowRequestCard = { notification.type = 'follow' } }) + this.hideApproveConfirmDialog() }, denyUser () { + if (this.shouldConfirmDeny) { + this.showDenyConfirmDialog() + } else { + this.doDeny() + } + }, + doDeny () { const notifId = this.findFollowRequestNotificationId() this.$store.state.api.backendInteractor.denyUser({ id: this.user.id }) .then(() => { this.$store.dispatch('dismissNotificationLocal', { id: notifId }) this.$store.dispatch('removeFollowRequest', this.user) }) + this.hideDenyConfirmDialog() + } + }, + computed: { + mergedConfig () { + return this.$store.getters.mergedConfig + }, + shouldConfirmApprove () { + return this.mergedConfig.modalOnApproveFollow + }, + shouldConfirmDeny () { + return this.mergedConfig.modalOnDenyFollow } } } diff --git a/src/components/follow_request_card/follow_request_card.vue b/src/components/follow_request_card/follow_request_card.vue index eb222cc7..55b65112 100644 --- a/src/components/follow_request_card/follow_request_card.vue +++ b/src/components/follow_request_card/follow_request_card.vue @@ -14,6 +14,28 @@ {{ $t('user_card.deny') }} + + + {{ $t('user_card.approve_confirm', { user: user.screen_name_ui }) }} + + + {{ $t('user_card.deny_confirm', { user: user.screen_name_ui }) }} + + diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index 265aaee0..0ce8892e 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -8,6 +8,7 @@ import Report from '../report/report.vue' import UserLink from '../user_link/user_link.vue' import RichContent from 'src/components/rich_content/rich_content.jsx' import UserPopover from '../user_popover/user_popover.vue' +import ConfirmModal from '../confirm_modal/confirm_modal.vue' import { isStatusNotification } from '../../services/notification_utils/notification_utils.js' import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' @@ -43,7 +44,9 @@ const Notification = { return { statusExpanded: false, betterShadow: this.$store.state.interface.browserSupport.cssFilter, - unmuted: false + unmuted: false, + showingApproveConfirmDialog: false, + showingDenyConfirmDialog: false } }, props: ['notification'], @@ -56,7 +59,8 @@ const Notification = { Report, RichContent, UserPopover, - UserLink + UserLink, + ConfirmModal }, methods: { toggleStatusExpanded () { @@ -71,7 +75,26 @@ const Notification = { toggleMute () { this.unmuted = !this.unmuted }, + showApproveConfirmDialog () { + this.showingApproveConfirmDialog = true + }, + hideApproveConfirmDialog () { + this.showingApproveConfirmDialog = false + }, + showDenyConfirmDialog () { + this.showingDenyConfirmDialog = true + }, + hideDenyConfirmDialog () { + this.showingDenyConfirmDialog = false + }, approveUser () { + if (this.shouldConfirmApprove) { + this.showApproveConfirmDialog() + } else { + this.doApprove() + } + }, + doApprove () { this.$store.state.api.backendInteractor.approveUser({ id: this.user.id }) this.$store.dispatch('removeFollowRequest', this.user) this.$store.dispatch('markSingleNotificationAsSeen', { id: this.notification.id }) @@ -83,6 +106,13 @@ const Notification = { }) }, denyUser () { + if (this.shouldConfirmDeny) { + this.showDenyConfirmDialog() + } else { + this.doDeny() + } + }, + doDeny () { this.$store.state.api.backendInteractor.denyUser({ id: this.user.id }) .then(() => { this.$store.dispatch('dismissNotificationLocal', { id: this.notification.id }) @@ -117,6 +147,15 @@ const Notification = { isStatusNotification () { return isStatusNotification(this.notification.type) }, + mergedConfig () { + return this.$store.getters.mergedConfig + }, + shouldConfirmApprove () { + return this.mergedConfig.modalOnApproveFollow + }, + shouldConfirmDeny () { + return this.mergedConfig.modalOnDenyFollow + }, ...mapState({ currentUser: state => state.users.currentUser }) diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index f1aa5420..e1ea42ad 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -243,6 +243,28 @@ + + + {{ $t('user_card.approve_confirm', { user: user.screen_name_ui }) }} + + + {{ $t('user_card.deny_confirm', { user: user.screen_name_ui }) }} + + diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index 906c3758..9de3ed81 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -181,6 +181,16 @@ {{ $t('settings.confirm_dialogs_logout') }} +
  • + + {{ $t('settings.confirm_dialogs_approve_follow') }} + +
  • +
  • + + {{ $t('settings.confirm_dialogs_deny_follow') }} + +
  • diff --git a/src/modules/config.js b/src/modules/config.js index a8949030..1df279a2 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -84,6 +84,8 @@ export const defaultState = { modalOnMute: undefined, // instance default modalOnDelete: undefined, // instance default modalOnLogout: undefined, // instance default + modalOnApproveFollow: undefined, // instance default + modalOnDenyFollow: undefined, // instance default playVideosInModal: false, useOneClickNsfw: false, useContainFit: true, diff --git a/src/modules/instance.js b/src/modules/instance.js index 6fc3830c..fcb6eecc 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -77,6 +77,8 @@ const defaultState = { modalOnMute: false, modalOnDelete: true, modalOnLogout: true, + modalOnApproveFollow: false, + modalOnDenyFollow: false, loginMethod: 'password', logo: '/static/logo.svg', logoMargin: '.2em', -- cgit v1.2.3-70-g09d2 From ce8101e60a1dc1a768f793a34fb6e9cca70b4858 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 27 Sep 2022 18:47:50 -0400 Subject: Add remove follower confirmation --- src/components/account_actions/account_actions.js | 20 +++++++++++++++- src/components/account_actions/account_actions.vue | 21 +++++++++++++++++ src/components/follow_card/follow_card.vue | 1 + .../remove_follower_button.js | 27 ++++++++++++++++++++-- .../remove_follower_button.vue | 21 +++++++++++++++++ src/components/settings_modal/tabs/general_tab.vue | 5 ++++ src/i18n/en.json | 5 ++++ src/modules/config.js | 1 + src/modules/instance.js | 1 + 9 files changed, 99 insertions(+), 3 deletions(-) (limited to 'src/modules') diff --git a/src/components/account_actions/account_actions.js b/src/components/account_actions/account_actions.js index 7dec0c3d..acd93e06 100644 --- a/src/components/account_actions/account_actions.js +++ b/src/components/account_actions/account_actions.js @@ -18,7 +18,8 @@ const AccountActions = { ], data () { return { - showingConfirmBlock: false + showingConfirmBlock: false, + showingConfirmRemoveFollower: false } }, components: { @@ -34,6 +35,12 @@ const AccountActions = { hideConfirmBlock () { this.showingConfirmBlock = false }, + showConfirmRemoveUserFromFollowers () { + this.showingConfirmRemoveFollower = true + }, + hideConfirmRemoveUserFromFollowers () { + this.showingConfirmRemoveFollower = false + }, showRepeats () { this.$store.dispatch('showReblogs', this.user.id) }, @@ -55,7 +62,15 @@ const AccountActions = { this.$store.dispatch('unblockUser', this.user.id) }, removeUserFromFollowers () { + if (!this.shouldConfirmRemoveUserFromFollowers) { + this.doRemoveUserFromFollowers() + } else { + this.showConfirmRemoveUserFromFollowers() + } + }, + doRemoveUserFromFollowers () { this.$store.dispatch('removeUserFromFollowers', this.user.id) + this.hideConfirmRemoveUserFromFollowers() }, reportUser () { this.$store.dispatch('openUserReportingModal', { userId: this.user.id }) @@ -71,6 +86,9 @@ const AccountActions = { shouldConfirmBlock () { return this.$store.getters.mergedConfig.modalOnBlock }, + shouldConfirmRemoveUserFromFollowers () { + return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers + }, ...mapState({ pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable }) diff --git a/src/components/account_actions/account_actions.vue b/src/components/account_actions/account_actions.vue index 161bab09..ce19291a 100644 --- a/src/components/account_actions/account_actions.vue +++ b/src/components/account_actions/account_actions.vue @@ -95,6 +95,27 @@ + + + + + + + diff --git a/src/components/follow_card/follow_card.vue b/src/components/follow_card/follow_card.vue index eff69fb2..bdb6b809 100644 --- a/src/components/follow_card/follow_card.vue +++ b/src/components/follow_card/follow_card.vue @@ -24,6 +24,7 @@ />