Commit a7d94cf2 authored by Enrique Alcántara's avatar Enrique Alcántara

Merge branch '229688-delete-account-modal' into 'master'

Update delete account modal

Closes #229688

See merge request gitlab-org/gitlab!37816
parents 9ff8e0be 241d76fd
<script>
/* eslint-disable vue/no-v-html */
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
import { GlModal } from '@gitlab/ui';
import { __, s__, sprintf } from '~/locale';
import csrf from '~/lib/utils/csrf';
export default {
components: {
DeprecatedModal,
GlModal,
},
props: {
actionUrl: {
......@@ -55,21 +55,34 @@ You are about to permanently delete %{yourAccount}, and all of the issues, merge
Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
{
yourAccount: `<strong>${s__('Profiles|your account')}</strong>`,
deleteAccount: `<strong>${s__('Profiles|Delete Account')}</strong>`,
deleteAccount: `<strong>${s__('Profiles|Delete account')}</strong>`,
},
false,
);
},
},
methods: {
primaryProps() {
return {
text: s__('Delete account'),
attributes: [{ variant: 'danger' }, { category: 'primary' }, { disabled: !this.canSubmit }],
};
},
cancelProps() {
return {
text: s__('Cancel'),
};
},
canSubmit() {
if (this.confirmWithPassword) {
return this.enteredPassword !== '';
}
return this.enteredUsername === this.username;
},
},
methods: {
onSubmit() {
if (!this.canSubmit) {
return;
}
this.$refs.form.submit();
},
},
......@@ -77,42 +90,39 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
</script>
<template>
<deprecated-modal
id="delete-account-modal"
:title="s__('Profiles|Delete your account?')"
:text="text"
:primary-button-label="s__('Profiles|Delete account')"
:submit-disabled="!canSubmit()"
kind="danger"
@submit="onSubmit"
<gl-modal
modal-id="delete-account-modal"
title="Profiles"
:action-primary="primaryProps"
:action-cancel="cancelProps"
:ok-disabled="!canSubmit"
@primary="onSubmit"
>
<template #body="props">
<p v-html="props.text"></p>
<p v-html="text"></p>
<form ref="form" :action="actionUrl" method="post">
<input type="hidden" name="_method" value="delete" />
<input :value="csrfToken" type="hidden" name="authenticity_token" />
<form ref="form" :action="actionUrl" method="post">
<input type="hidden" name="_method" value="delete" />
<input :value="csrfToken" type="hidden" name="authenticity_token" />
<p id="input-label" v-html="inputLabel"></p>
<p id="input-label" v-html="inputLabel"></p>
<input
v-if="confirmWithPassword"
v-model="enteredPassword"
name="password"
class="form-control"
type="password"
data-qa-selector="password_confirmation_field"
aria-labelledby="input-label"
/>
<input
v-else
v-model="enteredUsername"
name="username"
class="form-control"
type="text"
aria-labelledby="input-label"
/>
</form>
</template>
</deprecated-modal>
<input
v-if="confirmWithPassword"
v-model="enteredPassword"
name="password"
class="form-control"
type="password"
data-qa-selector="password_confirmation_field"
aria-labelledby="input-label"
/>
<input
v-else
v-model="enteredUsername"
name="username"
class="form-control"
type="text"
aria-labelledby="input-label"
/>
</form>
</gl-modal>
</template>
......@@ -30,6 +30,9 @@ export default () => {
},
mounted() {
deleteAccountButton.classList.remove('disabled');
deleteAccountButton.addEventListener('click', () => {
this.$root.$emit('bv::show::modal', 'delete-account-modal', '#delete-account-button');
});
},
render(createElement) {
return createElement('delete-account-modal', {
......
......@@ -55,8 +55,8 @@
= s_('Profiles|Deleting an account has the following effects:')
= render 'users/deletion_guidance', user: current_user
%button#delete-account-button.btn.btn-danger.disabled{ data: { toggle: 'modal',
target: '#delete-account-modal', qa_selector: 'delete_account_button' } }
-# Delete button here
%button#delete-account-button.btn.btn-danger.disabled{ data: { qa_selector: 'delete_account_button' } }
= s_('Profiles|Delete account')
#delete-account-modal{ data: { action_url: user_registration_path,
......
......@@ -7947,6 +7947,9 @@ msgstr ""
msgid "Delete Snippet"
msgstr ""
msgid "Delete account"
msgstr ""
msgid "Delete artifacts"
msgstr ""
......@@ -18724,15 +18727,9 @@ msgstr ""
msgid "Profiles|Default notification email"
msgstr ""
msgid "Profiles|Delete Account"
msgstr ""
msgid "Profiles|Delete account"
msgstr ""
msgid "Profiles|Delete your account?"
msgstr ""
msgid "Profiles|Deleting an account has the following effects:"
msgstr ""
......
import Vue from 'vue';
import { TEST_HOST } from 'helpers/test_constants';
import mountComponent from 'helpers/vue_mount_component_helper';
import { merge } from 'lodash';
import { mount } from '@vue/test-utils';
import deleteAccountModal from '~/profile/account/components/delete_account_modal.vue';
const GlModalStub = {
name: 'gl-modal-stub',
template: `
<div>
<slot></slot>
</div>
`,
};
describe('DeleteAccountModal component', () => {
const actionUrl = `${TEST_HOST}/delete/user`;
const username = 'hasnoname';
let Component;
let wrapper;
let vm;
beforeEach(() => {
Component = Vue.extend(deleteAccountModal);
});
const createWrapper = (options = {}) => {
wrapper = mount(
deleteAccountModal,
merge(
{},
{
propsData: {
actionUrl,
username,
},
stubs: {
GlModal: GlModalStub,
},
},
options,
),
);
vm = wrapper.vm;
};
afterEach(() => {
vm.$destroy();
wrapper.destroy();
wrapper = null;
vm = null;
});
const findElements = () => {
......@@ -23,16 +51,16 @@ describe('DeleteAccountModal component', () => {
return {
form: vm.$refs.form,
input: vm.$el.querySelector(`[name="${confirmation}"]`),
submitButton: vm.$el.querySelector('.btn-danger'),
};
};
const findModal = () => wrapper.find(GlModalStub);
describe('with password confirmation', () => {
beforeEach(done => {
vm = mountComponent(Component, {
actionUrl,
confirmWithPassword: true,
username,
createWrapper({
propsData: {
confirmWithPassword: true,
},
});
vm.isOpen = true;
......@@ -43,7 +71,7 @@ describe('DeleteAccountModal component', () => {
});
it('does not accept empty password', done => {
const { form, input, submitButton } = findElements();
const { form, input } = findElements();
jest.spyOn(form, 'submit').mockImplementation(() => {});
input.value = '';
input.dispatchEvent(new Event('input'));
......@@ -51,8 +79,8 @@ describe('DeleteAccountModal component', () => {
Vue.nextTick()
.then(() => {
expect(vm.enteredPassword).toBe(input.value);
expect(submitButton).toHaveAttr('disabled', 'disabled');
submitButton.click();
expect(findModal().attributes('ok-disabled')).toBe('true');
findModal().vm.$emit('primary');
expect(form.submit).not.toHaveBeenCalled();
})
......@@ -61,7 +89,7 @@ describe('DeleteAccountModal component', () => {
});
it('submits form with password', done => {
const { form, input, submitButton } = findElements();
const { form, input } = findElements();
jest.spyOn(form, 'submit').mockImplementation(() => {});
input.value = 'anything';
input.dispatchEvent(new Event('input'));
......@@ -69,8 +97,8 @@ describe('DeleteAccountModal component', () => {
Vue.nextTick()
.then(() => {
expect(vm.enteredPassword).toBe(input.value);
expect(submitButton).not.toHaveAttr('disabled', 'disabled');
submitButton.click();
expect(findModal().attributes('ok-disabled')).toBeUndefined();
findModal().vm.$emit('primary');
expect(form.submit).toHaveBeenCalled();
})
......@@ -81,10 +109,10 @@ describe('DeleteAccountModal component', () => {
describe('with username confirmation', () => {
beforeEach(done => {
vm = mountComponent(Component, {
actionUrl,
confirmWithPassword: false,
username,
createWrapper({
propsData: {
confirmWithPassword: false,
},
});
vm.isOpen = true;
......@@ -95,7 +123,7 @@ describe('DeleteAccountModal component', () => {
});
it('does not accept wrong username', done => {
const { form, input, submitButton } = findElements();
const { form, input } = findElements();
jest.spyOn(form, 'submit').mockImplementation(() => {});
input.value = 'this is wrong';
input.dispatchEvent(new Event('input'));
......@@ -103,8 +131,8 @@ describe('DeleteAccountModal component', () => {
Vue.nextTick()
.then(() => {
expect(vm.enteredUsername).toBe(input.value);
expect(submitButton).toHaveAttr('disabled', 'disabled');
submitButton.click();
expect(findModal().attributes('ok-disabled')).toBe('true');
findModal().vm.$emit('primary');
expect(form.submit).not.toHaveBeenCalled();
})
......@@ -113,7 +141,7 @@ describe('DeleteAccountModal component', () => {
});
it('submits form with correct username', done => {
const { form, input, submitButton } = findElements();
const { form, input } = findElements();
jest.spyOn(form, 'submit').mockImplementation(() => {});
input.value = username;
input.dispatchEvent(new Event('input'));
......@@ -121,8 +149,8 @@ describe('DeleteAccountModal component', () => {
Vue.nextTick()
.then(() => {
expect(vm.enteredUsername).toBe(input.value);
expect(submitButton).not.toHaveAttr('disabled', 'disabled');
submitButton.click();
expect(findModal().attributes('ok-disabled')).toBeUndefined();
findModal().vm.$emit('primary');
expect(form.submit).toHaveBeenCalled();
})
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment