Add checkboxes to delete posts/comments

- fix tests
- rename files/directory to DeleteData to be more accurate
This commit is contained in:
Matt Rider 2019-06-12 15:07:16 -03:00
parent fc8792e7af
commit 83c7773d1b
5 changed files with 122 additions and 116 deletions

View File

@ -1,5 +1,5 @@
import { config, mount, createLocalVue } from '@vue/test-utils' import { mount, createLocalVue } from '@vue/test-utils'
import DeleteAccount from './DeleteAccount.vue' import DeleteData from './DeleteData.vue'
import Styleguide from '@human-connection/styleguide' import Styleguide from '@human-connection/styleguide'
import Vuex from 'vuex' import Vuex from 'vuex'
@ -7,20 +7,18 @@ const localVue = createLocalVue()
localVue.use(Vuex) localVue.use(Vuex)
localVue.use(Styleguide) localVue.use(Styleguide)
config.stubs['b-switch'] = '<span><slot /></span>'
config.stubs['b-checkbox'] = '<span><slot /></span>'
describe('DeleteAccount.vue', () => { describe('DeleteData.vue', () => {
let mocks let mocks
let wrapper let wrapper
let getters let getters
let actions let actions
let deleteAccountBtn let deleteAccountBtn
let enableDeletionInput let enableDeletionInput
let enablePostDeletionInput let enableContributionDeletionCheckbox
let enableCommentDeletionInput let enableCommentDeletionCheckbox
const deleteAccountName = 'Delete MyAccount' const deleteAccountName = 'Delete MyAccount'
const deletePostsMessage = 'Delete my 2 posts' const deleteContributionsMessage = 'Delete my 2 posts'
const deleteCommentsMessage = 'Delete my 3 comments' const deleteCommentsMessage = 'Delete my 3 comments'
beforeEach(() => { beforeEach(() => {
@ -31,7 +29,7 @@ describe('DeleteAccount.vue', () => {
.fn() .fn()
.mockResolvedValueOnce({ .mockResolvedValueOnce({
data: { data: {
DeleteAccount: { DeleteData: {
id: 'u343', id: 'u343',
}, },
}, },
@ -62,7 +60,7 @@ describe('DeleteAccount.vue', () => {
getters, getters,
actions, actions,
}) })
return mount(DeleteAccount, { mocks, localVue, store }) return mount(DeleteData, { mocks, localVue, store })
} }
beforeEach(() => { beforeEach(() => {
@ -111,9 +109,9 @@ describe('DeleteAccount.vue', () => {
}) })
it("deletes a user's posts if requested", () => { it("deletes a user's posts if requested", () => {
mocks.$t.mockImplementation(() => deletePostsMessage) mocks.$t.mockImplementation(() => deleteContributionsMessage)
enablePostDeletionInput = wrapper.find('.enable-post-deletion-input input') enableContributionDeletionCheckbox = wrapper.findAll('.checkbox-container input').at(0)
enablePostDeletionInput.setValue(deletePostsMessage) enableContributionDeletionCheckbox.trigger('click')
deleteAccountBtn.trigger('click') deleteAccountBtn.trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith( expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
expect.objectContaining({ expect.objectContaining({
@ -127,8 +125,8 @@ describe('DeleteAccount.vue', () => {
it("deletes a user's comments if requested", () => { it("deletes a user's comments if requested", () => {
mocks.$t.mockImplementation(() => deleteCommentsMessage) mocks.$t.mockImplementation(() => deleteCommentsMessage)
enableCommentDeletionInput = wrapper.find('.enable-comment-deletion-input input') enableCommentDeletionCheckbox = wrapper.findAll('.checkbox-container input').at(1)
enableCommentDeletionInput.setValue(deleteCommentsMessage) enableCommentDeletionCheckbox.trigger('click')
deleteAccountBtn.trigger('click') deleteAccountBtn.trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith( expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
expect.objectContaining({ expect.objectContaining({
@ -141,12 +139,12 @@ describe('DeleteAccount.vue', () => {
}) })
it("deletes a user's posts and comments if requested", () => { it("deletes a user's posts and comments if requested", () => {
mocks.$t.mockImplementation(() => deletePostsMessage) mocks.$t.mockImplementation(() => deleteContributionsMessage)
enablePostDeletionInput = wrapper.find('.enable-post-deletion-input input') enableContributionDeletionCheckbox = wrapper.findAll('.checkbox-container input').at(0)
enablePostDeletionInput.setValue(deletePostsMessage) enableContributionDeletionCheckbox.trigger('click')
mocks.$t.mockImplementation(() => deleteCommentsMessage) mocks.$t.mockImplementation(() => deleteCommentsMessage)
enableCommentDeletionInput = wrapper.find('.enable-comment-deletion-input input') enableCommentDeletionCheckbox = wrapper.findAll('.checkbox-container input').at(1)
enableCommentDeletionInput.setValue(deleteCommentsMessage) enableCommentDeletionCheckbox.trigger('click')
deleteAccountBtn.trigger('click') deleteAccountBtn.trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith( expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
expect.objectContaining({ expect.objectContaining({
@ -163,7 +161,7 @@ describe('DeleteAccount.vue', () => {
expect(mocks.$toast.success).toHaveBeenCalledTimes(1) expect(mocks.$toast.success).toHaveBeenCalledTimes(1)
}) })
it('updates the user in the store', async () => { it('redirect the user to the homepage', async () => {
await deleteAccountBtn.trigger('click') await deleteAccountBtn.trigger('click')
expect(mocks.$router.history.push).toHaveBeenCalledWith('/') expect(mocks.$router.history.push).toHaveBeenCalledWith('/')
}) })

View File

@ -4,10 +4,10 @@
<ds-space /> <ds-space />
<ds-container> <ds-container>
<ds-flex> <ds-flex>
<ds-flex-item :width="{ base: '100%', sm: 0.75, md: 0.5, lg: 0.5 }"> <ds-flex-item :width="{ base: '22%', sm: '12%', md: '12%', lg: '8%' }">
<ds-icon name="warning" size="xxx-large" class="delete-warning-icon" /> <ds-icon name="warning" size="xxx-large" class="delete-warning-icon" />
</ds-flex-item> </ds-flex-item>
<ds-flex-item :width="{ base: '100%', sm: 5.25, md: 2.75, lg: 5.5 }"> <ds-flex-item :width="{ base: '78%', sm: '88%', md: '88%', lg: '92%' }">
<ds-heading>{{ $t('settings.deleteUserAccount.name') }}</ds-heading> <ds-heading>{{ $t('settings.deleteUserAccount.name') }}</ds-heading>
</ds-flex-item> </ds-flex-item>
<ds-space /> <ds-space />
@ -20,62 +20,33 @@
<ds-container> <ds-container>
<transition name="slide-up"> <transition name="slide-up">
<div v-if="deleteEnabled"> <div v-if="deleteEnabled">
<div <label v-if="currentUser.contributionsCount" class="checkbox-container">
class="delete-input-label" <input type="checkbox" v-model="deleteContributions" />
v-html=" <span class="checkmark"></span>
$t('settings.deleteUserAccount.pleaseConfirm', { {{
confirm: $t('settings.deleteUserAccount.contributionsCount', { $t('settings.deleteUserAccount.contributionsCount', {
count: currentUser.contributionsCount, count: currentUser.contributionsCount,
}),
}) })
" }}
></div> </label>
<ds-space margin-bottom="xx-small" /> <ds-space margin-bottom="small" />
<ds-flex :gutter="{ base: 'xx-small', md: 'small', lg: 'large' }"> <label v-if="currentUser.commentsCount" class="checkbox-container">
<ds-flex-item <input type="checkbox" v-model="deleteComments" />
v-if="currentUser.contributionsCount" <span class="checkmark"></span>
:width="{ base: '100%', sm: '100%', md: '100%', lg: '100%' }" {{
> $t('settings.deleteUserAccount.commentsCount', {
<ds-input
v-model="deleteContributionsValue"
@input="enableDeletion"
class="enable-post-deletion-input"
/>
</ds-flex-item>
</ds-flex>
<ds-space margin-bottom="xx-small" />
<div
class="delete-input-label"
v-html="
$t('settings.deleteUserAccount.pleaseConfirm', {
confirm: $t('settings.deleteUserAccount.commentsCount', {
count: currentUser.commentsCount, count: currentUser.commentsCount,
}),
}) })
" }}
></div> </label>
<ds-space margin-bottom="xx-small" /> <ds-space margin-bottom="small" />
<ds-flex :gutter="{ base: 'xx-small', md: 'small', lg: 'large' }">
<ds-flex-item
v-if="currentUser.commentsCount"
:width="{ base: '100%', sm: '100%', md: '100%', lg: '100%' }"
>
<ds-input
v-model="deleteCommentsValue"
@input="enableDeletion"
class="enable-comment-deletion-input"
/>
</ds-flex-item>
<ds-flex-item :width="{ base: '100%', sm: '100%', md: '100%', lg: '100%' }">
<ds-section id="delete-user-account-warning"> <ds-section id="delete-user-account-warning">
<div v-html="$t('settings.deleteUserAccount.accountWarning')"></div> <div v-html="$t('settings.deleteUserAccount.accountWarning')"></div>
</ds-section> </ds-section>
</ds-flex-item>
</ds-flex>
</div> </div>
</transition> </transition>
</ds-container> </ds-container>
<template slot="footer"> <template slot="footer" class="delete-data-footer">
<ds-container> <ds-container>
<div <div
class="delete-input-label" class="delete-input-label"
@ -91,12 +62,7 @@
/> />
</ds-flex-item> </ds-flex-item>
<ds-flex-item :width="{ base: '100%', sm: '100%', md: '100%', lg: 1 }"> <ds-flex-item :width="{ base: '100%', sm: '100%', md: '100%', lg: 1 }">
<ds-button <ds-button icon="trash" danger :disabled="!deleteEnabled" @click="handleSubmit">
icon="trash"
danger
:disabled="isLoading || !deleteEnabled"
@click="handleSubmit"
>
{{ $t('settings.deleteUserAccount.name') }} {{ $t('settings.deleteUserAccount.name') }}
</ds-button> </ds-button>
</ds-flex-item> </ds-flex-item>
@ -111,16 +77,12 @@ import { mapGetters, mapActions } from 'vuex'
import gql from 'graphql-tag' import gql from 'graphql-tag'
export default { export default {
name: 'DeleteAccount', name: 'DeleteData',
data() { data() {
return { return {
deleteContributions: false, deleteContributions: false,
deleteComments: false, deleteComments: false,
deleteEnabled: false, deleteEnabled: false,
isLoading: false,
enableDeletionValue: '',
deleteContributionsValue: '',
deleteCommentsValue: '',
} }
}, },
computed: { computed: {
@ -135,23 +97,6 @@ export default {
enableDeletion() { enableDeletion() {
if (this.enableDeletionValue === this.currentUser.name) { if (this.enableDeletionValue === this.currentUser.name) {
this.deleteEnabled = true this.deleteEnabled = true
this.focused = false
}
if (
this.deleteContributionsValue ===
this.$t('settings.deleteUserAccount.contributionsCount', {
count: this.currentUser.contributionsCount,
})
) {
this.deleteContributions = true
}
if (
this.deleteCommentsValue ===
this.$t('settings.deleteUserAccount.commentsCount', {
count: this.currentUser.commentsCount,
})
) {
this.deleteComments = true
} }
}, },
handleSubmit() { handleSubmit() {
@ -190,9 +135,72 @@ export default {
color: $color-danger; color: $color-danger;
} }
.enable-deletion-input input:focus, .checkbox-container {
.enable-post-deletion-input input:focus, display: block;
.enable-comment-deletion-input input:focus { position: relative;
padding-left: 35px;
cursor: pointer;
font-size: $font-size-large;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.checkbox-container input {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
.checkmark {
position: absolute;
top: 0;
left: 0;
height: 20px;
width: 20px;
border: 2px solid $background-color-inverse-softer;
background-color: $background-color-base;
border-radius: $border-radius-x-large;
}
.checkbox-container:hover input ~ .checkmark {
background-color: $background-color-softest;
}
/* When the checkbox is checked, add a blue background */
.checkbox-container input:checked ~ .checkmark {
background-color: $background-color-danger-active;
}
/* Create the checkmark/indicator (hidden when not checked) */
.checkmark:after {
content: '';
position: absolute;
display: none;
}
/* Show the checkmark when checked */
.checkbox-container input:checked ~ .checkmark:after {
display: block;
}
/* Style the checkmark/indicator */
.checkbox-container .checkmark:after {
left: 6px;
top: 3px;
width: 5px;
height: 10px;
border: solid $background-color-base;
border-width: 0 $border-size-large $border-size-large 0;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
.enable-deletion-input input:focus {
border-color: $border-color-danger; border-color: $border-color-danger;
} }
@ -204,7 +212,7 @@ b.is-danger {
color: $text-color-danger; color: $text-color-danger;
} }
.ds-card-footer { .delete-data-footer {
border-top: $border-size-base solid $border-color-softest; border-top: $border-size-base solid $border-color-softest;
background-color: $background-color-danger-inverse; background-color: $background-color-danger-inverse;
} }

View File

@ -74,13 +74,13 @@
"name": "Daten herunterladen" "name": "Daten herunterladen"
}, },
"deleteUserAccount": { "deleteUserAccount": {
"name": "Mein Benutzerkonto löschen", "name": "Daten löschen",
"contributionsCount": "Meine {count} Beiträge löschen", "contributionsCount": "Meine {count} Beiträge löschen",
"commentsCount": "Meine {count} Kommentare löschen", "commentsCount": "Meine {count} Kommentare löschen",
"accountDescription": "Seien Sie sich bewusst, dass Ihre Beiträge und Kommentare für unsere Community wichtig sind. Wenn du sie trotzdem löschen möchtest, musst du dies unten auswählen.", "accountDescription": "Sie dir bewusst, dass deine Beiträge und Kommentare für unsere Community wichtig sind. Wenn du sie trotzdem löschen möchtest, musst du sie unten markieren.",
"accountWarning": "Dein Benutzerkonto, die Beiträge, etc. kannst Du nach dem Löschen <b>WEDER VERWALTEN NOCH WIEDERHERSTELLEN!</b>", "accountWarning": "Dein Konto, Beiträge oder Kommentare kannst Du nach dem Löschen <b>WEDER VERWALTEN NOCH WIEDERHERSTELLEN!</b>",
"success": "Konto erfolgreich gelöscht", "success": "Konto erfolgreich gelöscht",
"pleaseConfirm": "<b class='is-danger'>Zerstörerische Aktion!</b> Geben Sie <b>{confirm}</b> ein, um zu bestätigen." "pleaseConfirm": "<b class='is-danger'>Zerstörerische Aktion!</b> Gib <b>{confirm}</b> ein, um zu bestätigen."
}, },
"organizations": { "organizations": {
"name": "Meine Organisationen" "name": "Meine Organisationen"

View File

@ -74,11 +74,11 @@
"name": "Download Data" "name": "Download Data"
}, },
"deleteUserAccount": { "deleteUserAccount": {
"name": "Delete my User Account", "name": "Delete Data",
"contributionsCount": "Delete my {count} posts", "contributionsCount": "Delete my {count} posts",
"commentsCount": "Delete my {count} comments", "commentsCount": "Delete my {count} comments",
"accountDescription": "Be aware that your Post and Comments are important to our community. If you still want to delete them, you have to choose so below.", "accountDescription": "Be aware that your Post and Comments are important to our community. If you still choose to delete them, you have to mark them below.",
"accountWarning": "You <b>CAN'T MANAGE</b> and <b>CAN'T RECOVER</b> your Account, Posts... after deleting your account!", "accountWarning": "You <b>CAN'T MANAGE</b> and <b>CAN'T RECOVER</b> your Account, Posts, or Comments after deleting your account!",
"success": "Account successfully deleted", "success": "Account successfully deleted",
"pleaseConfirm": "<b class='is-danger'>Destructive action!</b> Type <b>{confirm}</b> to confirm" "pleaseConfirm": "<b class='is-danger'>Destructive action!</b> Type <b>{confirm}</b> to confirm"
}, },

View File

@ -1,13 +1,13 @@
<template> <template>
<delete-account /> <delete-data />
</template> </template>
<script> <script>
import DeleteAccount from '~/components/DeleteAccount/DeleteAccount.vue' import DeleteData from '~/components/DeleteData/DeleteData.vue'
export default { export default {
components: { components: {
DeleteAccount, DeleteData,
}, },
} }
</script> </script>