From 1ff2948aeb485ef48a4add6310ba8fb9d43d262c Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Wed, 9 Feb 2022 15:17:06 -0500
Subject: Add setting entries for whether to show confirmation dialogs

---
 src/components/settings_modal/tabs/general_tab.vue | 35 ++++++++++++++++++++++
 1 file changed, 35 insertions(+)

(limited to 'src/components/settings_modal/tabs/general_tab.vue')

diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index 582cb288..906c3758 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -148,6 +148,41 @@
             </SizeSetting>
           </div>
         </li>
+        <li class="select-multiple">
+          <span class="label">{{ $t('settings.confirm_dialogs') }}</span>
+          <ul class="option-list">
+            <li>
+              <BooleanSetting path="modalOnRepeat">
+                {{ $t('settings.confirm_dialogs_repeat') }}
+              </BooleanSetting>
+            </li>
+            <li>
+              <BooleanSetting path="modalOnUnfollow">
+                {{ $t('settings.confirm_dialogs_unfollow') }}
+              </BooleanSetting>
+            </li>
+            <li>
+              <BooleanSetting path="modalOnBlock">
+                {{ $t('settings.confirm_dialogs_block') }}
+              </BooleanSetting>
+            </li>
+            <li>
+              <BooleanSetting path="modalOnMute">
+                {{ $t('settings.confirm_dialogs_mute') }}
+              </BooleanSetting>
+            </li>
+            <li>
+              <BooleanSetting path="modalOnDelete">
+                {{ $t('settings.confirm_dialogs_delete') }}
+              </BooleanSetting>
+            </li>
+            <li>
+              <BooleanSetting path="modalOnLogout">
+                {{ $t('settings.confirm_dialogs_logout') }}
+              </BooleanSetting>
+            </li>
+          </ul>
+        </li>
       </ul>
     </div>
     <div class="setting-item">
-- 
cgit v1.2.3-70-g09d2


From 547e85c7c6f9bf8779cc06344c4eebaaa8f9d775 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
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/components/settings_modal/tabs/general_tab.vue')

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') }}
       </button>
     </div>
+    <teleport to="#modal">
+      <confirm-modal
+        v-if="showingApproveConfirmDialog"
+        :title="$t('user_card.approve_confirm_title')"
+        :confirm-text="$t('user_card.approve_confirm_accept_button')"
+        :cancel-text="$t('user_card.approve_confirm_cancel_button')"
+        @accepted="doApprove"
+        @cancelled="hideApproveConfirmDialog"
+      >
+        {{ $t('user_card.approve_confirm', { user: user.screen_name_ui }) }}
+      </confirm-modal>
+      <confirm-modal
+        v-if="showingDenyConfirmDialog"
+        :title="$t('user_card.deny_confirm_title')"
+        :confirm-text="$t('user_card.deny_confirm_accept_button')"
+        :cancel-text="$t('user_card.deny_confirm_cancel_button')"
+        @accepted="doDeny"
+        @cancelled="hideDenyConfirmDialog"
+      >
+        {{ $t('user_card.deny_confirm', { user: user.screen_name_ui }) }}
+      </confirm-modal>
+    </teleport>
   </basic-user-card>
 </template>
 
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 @@
         </template>
       </div>
     </div>
+    <teleport to="#modal">
+      <confirm-modal
+        v-if="showingApproveConfirmDialog"
+        :title="$t('user_card.approve_confirm_title')"
+        :confirm-text="$t('user_card.approve_confirm_accept_button')"
+        :cancel-text="$t('user_card.approve_confirm_cancel_button')"
+        @accepted="doApprove"
+        @cancelled="hideApproveConfirmDialog"
+      >
+        {{ $t('user_card.approve_confirm', { user: user.screen_name_ui }) }}
+      </confirm-modal>
+      <confirm-modal
+        v-if="showingDenyConfirmDialog"
+        :title="$t('user_card.deny_confirm_title')"
+        :confirm-text="$t('user_card.deny_confirm_accept_button')"
+        :cancel-text="$t('user_card.deny_confirm_cancel_button')"
+        @accepted="doDeny"
+        @cancelled="hideDenyConfirmDialog"
+      >
+        {{ $t('user_card.deny_confirm', { user: user.screen_name_ui }) }}
+      </confirm-modal>
+    </teleport>
   </article>
 </template>
 
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') }}
               </BooleanSetting>
             </li>
+            <li>
+              <BooleanSetting path="modalOnApproveFollow">
+                {{ $t('settings.confirm_dialogs_approve_follow') }}
+              </BooleanSetting>
+            </li>
+            <li>
+              <BooleanSetting path="modalOnDenyFollow">
+                {{ $t('settings.confirm_dialogs_deny_follow') }}
+              </BooleanSetting>
+            </li>
           </ul>
         </li>
       </ul>
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 <tusooa@kazv.moe>
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/components/settings_modal/tabs/general_tab.vue')

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 @@
         </i18n-t>
       </confirm-modal>
     </teleport>
+    <teleport to="#modal">
+      <confirm-modal
+        v-if="showingConfirmRemoveFollower"
+        :title="$t('user_card.remove_follower_confirm_title')"
+        :confirm-text="$t('user_card.remove_follower_confirm_accept_button')"
+        :cancel-text="$t('user_card.remove_follower_confirm_cancel_button')"
+        @accepted="doRemoveUserFromFollowers"
+        @cancelled="hideConfirmRemoveUserFromFollowers"
+      >
+        <i18n-t
+          keypath="user_card.remove_follower_confirm"
+          tag="span"
+        >
+          <template #user>
+            <span
+              v-text="user.screen_name_ui"
+            />
+          </template>
+        </i18n-t>
+      </confirm-modal>
+    </teleport>
   </div>
 </template>
 
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 @@
         />
         <RemoveFollowerButton
           v-if="noFollowsYou && relationship.followed_by"
+          :user="user"
           :relationship="relationship"
           class="follow-card-button"
         />
diff --git a/src/components/remove_follower_button/remove_follower_button.js b/src/components/remove_follower_button/remove_follower_button.js
index e1a7531b..052a519f 100644
--- a/src/components/remove_follower_button/remove_follower_button.js
+++ b/src/components/remove_follower_button/remove_follower_button.js
@@ -1,10 +1,16 @@
+import ConfirmModal from '../confirm_modal/confirm_modal.vue'
+
 export default {
-  props: ['relationship'],
+  props: ['user', 'relationship'],
   data () {
     return {
-      inProgress: false
+      inProgress: false,
+      showingConfirmRemoveFollower: false
     }
   },
+  components: {
+    ConfirmModal
+  },
   computed: {
     label () {
       if (this.inProgress) {
@@ -12,14 +18,31 @@ export default {
       } else {
         return this.$t('user_card.remove_follower')
       }
+    },
+    shouldConfirmRemoveUserFromFollowers () {
+      return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers
     }
   },
   methods: {
+    showConfirmRemoveUserFromFollowers () {
+      this.showingConfirmRemoveFollower = true
+    },
+    hideConfirmRemoveUserFromFollowers () {
+      this.showingConfirmRemoveFollower = false
+    },
     onClick () {
+      if (!this.shouldConfirmRemoveUserFromFollowers) {
+        this.doRemoveUserFromFollowers()
+      } else {
+        this.showConfirmRemoveUserFromFollowers()
+      }
+    },
+    doRemoveUserFromFollowers () {
       this.inProgress = true
       this.$store.dispatch('removeUserFromFollowers', this.relationship.id).then(() => {
         this.inProgress = false
       })
+      this.hideConfirmRemoveUserFromFollowers()
     }
   }
 }
diff --git a/src/components/remove_follower_button/remove_follower_button.vue b/src/components/remove_follower_button/remove_follower_button.vue
index a3a4c242..0012aebd 100644
--- a/src/components/remove_follower_button/remove_follower_button.vue
+++ b/src/components/remove_follower_button/remove_follower_button.vue
@@ -7,6 +7,27 @@
     @click="onClick"
   >
     {{ label }}
+    <teleport to="#modal">
+      <confirm-modal
+        v-if="showingConfirmRemoveFollower"
+        :title="$t('user_card.remove_follower_confirm_title')"
+        :confirm-text="$t('user_card.remove_follower_confirm_accept_button')"
+        :cancel-text="$t('user_card.remove_follower_confirm_cancel_button')"
+        @accepted="doRemoveUserFromFollowers"
+        @cancelled="hideConfirmRemoveUserFromFollowers"
+      >
+        <i18n-t
+          keypath="user_card.remove_follower_confirm"
+          tag="span"
+        >
+          <template #user>
+            <span
+              v-text="user.screen_name_ui"
+            />
+          </template>
+        </i18n-t>
+      </confirm-modal>
+    </teleport>
   </button>
 </template>
 
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index 9de3ed81..703e94a0 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -191,6 +191,11 @@
                 {{ $t('settings.confirm_dialogs_deny_follow') }}
               </BooleanSetting>
             </li>
+            <li>
+              <BooleanSetting path="modalOnRemoveUserFromFollowers">
+                {{ $t('settings.confirm_dialogs_remove_follower') }}
+              </BooleanSetting>
+            </li>
           </ul>
         </li>
       </ul>
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 213f9cf0..ca022c82 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -429,6 +429,7 @@
     "confirm_dialogs_logout": "logging out",
     "confirm_dialogs_approve_follow": "approving a follower",
     "confirm_dialogs_deny_follow": "denying a follower",
+    "confirm_dialogs_remove_follower": "removing a follower",
     "mutes_and_blocks": "Mutes and Blocks",
     "data_import_export_tab": "Data import / export",
     "default_vis": "Default visibility scope",
@@ -964,6 +965,10 @@
     "per_day": "per day",
     "remote_follow": "Remote follow",
     "remove_follower": "Remove follower",
+    "remove_follower_confirm_title": "Remove follower confirmation",
+    "remove_follower_confirm_accept_button": "Remove",
+    "remove_follower_confirm_cancel_button": "Keep",
+    "remove_follower_confirm": "Do you really want to remove {user} from your followers?",
     "report": "Report",
     "statuses": "Statuses",
     "subscribe": "Subscribe",
diff --git a/src/modules/config.js b/src/modules/config.js
index 1df279a2..8e6b2c3d 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -86,6 +86,7 @@ export const defaultState = {
   modalOnLogout: undefined, // instance default
   modalOnApproveFollow: undefined, // instance default
   modalOnDenyFollow: undefined, // instance default
+  modalOnRemoveUserFromFollowers: undefined, // instance default
   playVideosInModal: false,
   useOneClickNsfw: false,
   useContainFit: true,
diff --git a/src/modules/instance.js b/src/modules/instance.js
index fcb6eecc..ce958907 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -79,6 +79,7 @@ const defaultState = {
   modalOnLogout: true,
   modalOnApproveFollow: false,
   modalOnDenyFollow: false,
+  modalOnRemoveUserFromFollowers: false,
   loginMethod: 'password',
   logo: '/static/logo.svg',
   logoMargin: '.2em',
-- 
cgit v1.2.3-70-g09d2

