feat: edit contact modal confirm discard (#199)
* feat(contact): add confirmation dialog for discarding unsaved changes in edit contact modal * chore: add GitHub Copilot instructions for project guidelines * feat(contact): update confirmation dialog logic for discarding unsaved changes in edit contact modal
This commit is contained in:
parent
b1aaf58097
commit
4ca0ef22c0
8
.github/copilot-instructions.md
vendored
Normal file
8
.github/copilot-instructions.md
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# GitHub Copilot Instructions
|
||||||
|
|
||||||
|
- Always include pt-BR translations for any new text added to the project.
|
||||||
|
- fazer.ai is always styled as-is, with a dot and lowercase letters. Never use Fazer.ai
|
||||||
|
- Always check if adding specs is necessary when modifying code.
|
||||||
|
- Evaluate if specs added are actually needed and not redundant. Specs should not be for documentation purposes only, they should cover expected behavior.
|
||||||
|
- Always evaluate if frontend changes are needed when modifying backend code, and vice versa.
|
||||||
|
- NEVER use `--` in `pnpm test -- <file>`. Just do `pnpm test <file>` directly
|
||||||
@ -61,7 +61,13 @@
|
|||||||
"EDIT_CONTACT": {
|
"EDIT_CONTACT": {
|
||||||
"BUTTON_LABEL": "Edit Contact",
|
"BUTTON_LABEL": "Edit Contact",
|
||||||
"TITLE": "Edit contact",
|
"TITLE": "Edit contact",
|
||||||
"DESC": "Edit contact details"
|
"DESC": "Edit contact details",
|
||||||
|
"CONFIRM_DISCARD": {
|
||||||
|
"TITLE": "Discard changes?",
|
||||||
|
"MESSAGE": "You have unsaved changes. Are you sure you want to discard them?",
|
||||||
|
"YES": "Discard",
|
||||||
|
"NO": "Keep editing"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"DELETE_CONTACT": {
|
"DELETE_CONTACT": {
|
||||||
"BUTTON_LABEL": "Delete Contact",
|
"BUTTON_LABEL": "Delete Contact",
|
||||||
|
|||||||
@ -61,7 +61,13 @@
|
|||||||
"EDIT_CONTACT": {
|
"EDIT_CONTACT": {
|
||||||
"BUTTON_LABEL": "Editar Contato",
|
"BUTTON_LABEL": "Editar Contato",
|
||||||
"TITLE": "Editar contato",
|
"TITLE": "Editar contato",
|
||||||
"DESC": "Alterar detalhes do contato"
|
"DESC": "Alterar detalhes do contato",
|
||||||
|
"CONFIRM_DISCARD": {
|
||||||
|
"TITLE": "Descartar alterações?",
|
||||||
|
"MESSAGE": "Você tem alterações não salvas. Tem certeza de que deseja descartá-las?",
|
||||||
|
"YES": "Descartar",
|
||||||
|
"NO": "Continuar editando"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"DELETE_CONTACT": {
|
"DELETE_CONTACT": {
|
||||||
"BUTTON_LABEL": "Excluir Contato",
|
"BUTTON_LABEL": "Excluir Contato",
|
||||||
|
|||||||
@ -64,6 +64,7 @@ export default {
|
|||||||
{ key: 'github', prefixURL: 'https://github.com/' },
|
{ key: 'github', prefixURL: 'https://github.com/' },
|
||||||
{ key: 'tiktok', prefixURL: 'https://tiktok.com/@' },
|
{ key: 'tiktok', prefixURL: 'https://tiktok.com/@' },
|
||||||
],
|
],
|
||||||
|
initialData: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
validations: {
|
validations: {
|
||||||
@ -100,8 +101,27 @@ export default {
|
|||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
|
hasUnsavedChanges() {
|
||||||
|
if (!this.initialData) return false;
|
||||||
|
const socialProfilesChanged = this.socialProfileKeys.some(
|
||||||
|
({ key }) =>
|
||||||
|
(this.socialProfileUserNames[key] || '') !==
|
||||||
|
(this.initialData.socialProfileUserNames[key] || '')
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
this.name !== this.initialData.name ||
|
||||||
|
this.email !== this.initialData.email ||
|
||||||
|
this.phoneNumber !== this.initialData.phoneNumber ||
|
||||||
|
this.companyName !== this.initialData.companyName ||
|
||||||
|
this.description !== this.initialData.description ||
|
||||||
|
this.city !== this.initialData.city ||
|
||||||
|
(this.country?.id || '') !== (this.initialData.countryId || '') ||
|
||||||
|
this.avatarFile !== null ||
|
||||||
|
socialProfilesChanged
|
||||||
|
);
|
||||||
|
},
|
||||||
setPhoneNumber() {
|
setPhoneNumber() {
|
||||||
if (this.parsePhoneNumber && this.parsePhoneNumber.countryCallingCode) {
|
if (this.parsePhoneNumber?.countryCallingCode) {
|
||||||
return this.phoneNumber;
|
return this.phoneNumber;
|
||||||
}
|
}
|
||||||
if (this.phoneNumber === '' && this.activeDialCode !== '') {
|
if (this.phoneNumber === '' && this.activeDialCode !== '') {
|
||||||
@ -175,6 +195,16 @@ export default {
|
|||||||
github: socialProfiles.github || '',
|
github: socialProfiles.github || '',
|
||||||
instagram: socialProfiles.instagram || '',
|
instagram: socialProfiles.instagram || '',
|
||||||
};
|
};
|
||||||
|
this.initialData = {
|
||||||
|
name: this.name,
|
||||||
|
email: this.email,
|
||||||
|
phoneNumber: this.phoneNumber,
|
||||||
|
companyName: this.companyName,
|
||||||
|
description: this.description,
|
||||||
|
city: this.city,
|
||||||
|
countryId: this.country.id,
|
||||||
|
socialProfileUserNames: { ...this.socialProfileUserNames },
|
||||||
|
};
|
||||||
},
|
},
|
||||||
getContactObject() {
|
getContactObject() {
|
||||||
if (this.country === null) {
|
if (this.country === null) {
|
||||||
@ -253,7 +283,7 @@ export default {
|
|||||||
},
|
},
|
||||||
async handleAvatarDelete() {
|
async handleAvatarDelete() {
|
||||||
try {
|
try {
|
||||||
if (this.contact && this.contact.id) {
|
if (this.contact?.id) {
|
||||||
await this.$store.dispatch('contacts/deleteAvatar', this.contact.id);
|
await this.$store.dispatch('contacts/deleteAvatar', this.contact.id);
|
||||||
useAlert(this.$t('CONTACT_FORM.DELETE_AVATAR.API.SUCCESS_MESSAGE'));
|
useAlert(this.$t('CONTACT_FORM.DELETE_AVATAR.API.SUCCESS_MESSAGE'));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,15 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onCancel() {
|
async onClose() {
|
||||||
|
const hasChanges = this.$refs.contactForm?.hasUnsavedChanges;
|
||||||
|
if (hasChanges) {
|
||||||
|
const shouldDiscard =
|
||||||
|
await this.$refs.confirmDiscardDialog.showConfirmation();
|
||||||
|
if (!shouldDiscard) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
this.$emit('cancel');
|
this.$emit('cancel');
|
||||||
},
|
},
|
||||||
onSuccess() {
|
onSuccess() {
|
||||||
@ -52,7 +60,7 @@ export default {
|
|||||||
<template>
|
<template>
|
||||||
<woot-modal
|
<woot-modal
|
||||||
v-model:show="localShow"
|
v-model:show="localShow"
|
||||||
:on-close="onCancel"
|
:on-close="onClose"
|
||||||
modal-type="right-aligned"
|
modal-type="right-aligned"
|
||||||
>
|
>
|
||||||
<div class="flex flex-col h-auto overflow-auto">
|
<div class="flex flex-col h-auto overflow-auto">
|
||||||
@ -63,12 +71,20 @@ export default {
|
|||||||
:header-content="$t('EDIT_CONTACT.DESC')"
|
:header-content="$t('EDIT_CONTACT.DESC')"
|
||||||
/>
|
/>
|
||||||
<ContactForm
|
<ContactForm
|
||||||
|
ref="contactForm"
|
||||||
:contact="contact"
|
:contact="contact"
|
||||||
:in-progress="uiFlags.isUpdating"
|
:in-progress="uiFlags.isUpdating"
|
||||||
:on-submit="onSubmit"
|
:on-submit="onSubmit"
|
||||||
@success="onSuccess"
|
@success="onSuccess"
|
||||||
@cancel="onCancel"
|
@cancel="onClose"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</woot-modal>
|
</woot-modal>
|
||||||
|
<woot-confirm-modal
|
||||||
|
ref="confirmDiscardDialog"
|
||||||
|
:title="$t('EDIT_CONTACT.CONFIRM_DISCARD.TITLE')"
|
||||||
|
:description="$t('EDIT_CONTACT.CONFIRM_DISCARD.MESSAGE')"
|
||||||
|
:confirm-label="$t('EDIT_CONTACT.CONFIRM_DISCARD.YES')"
|
||||||
|
:cancel-label="$t('EDIT_CONTACT.CONFIRM_DISCARD.NO')"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user