mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-15 21:57:22 +01:00
Feature: new "report a bug" modal (#13530)
* WIP: report a bug api/ui * fix lint * add USER_USERNAME * extend sendTxn tests / checks + fix bug report email * fix lint * add more checks to sendTxn - fix bug-report variables * fix lint / ci * fix test: reset email config url * fix test stub * fix tests * refactor the variables checks * lint. * move bug-report page as a modal * send user_email to the email * show true/false instead 1/0 * fix issues * fix footer report bug email if not logged in * fix styles/margins * prefill user's email * show facebook email if local email not existing * bugReportSuccessModal.vue * add BROWSER_UA to mail properties * extract bugReportLogic to its own lib file for unit test * test api validators * fix lint
This commit is contained in:
243
website/client/src/components/bugReportModal.vue
Normal file
243
website/client/src/components/bugReportModal.vue
Normal file
@@ -0,0 +1,243 @@
|
||||
<template>
|
||||
<b-modal
|
||||
:id="modalId"
|
||||
size="md"
|
||||
:hide-footer="true"
|
||||
>
|
||||
<div
|
||||
slot="modal-header"
|
||||
class="bug-report-modal-header"
|
||||
>
|
||||
<h2 v-once>
|
||||
{{ $t('reportBug') }}
|
||||
</h2>
|
||||
|
||||
<div v-once class="report-bug-header-describe">
|
||||
{{ $t('reportBugHeaderDescribe') }}
|
||||
</div>
|
||||
|
||||
<div class="dialog-close">
|
||||
<close-icon @click="close()" :purple="true"/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<form
|
||||
class="form"
|
||||
@submit.prevent.stop="sendBugReport()"
|
||||
>
|
||||
<div
|
||||
class="form-group"
|
||||
>
|
||||
<label
|
||||
v-once
|
||||
for="emailInput"
|
||||
>
|
||||
{{ $t('email') }}
|
||||
</label>
|
||||
<div class="mb-2 description-label" v-once>
|
||||
{{ $t('reportEmailText') }}
|
||||
</div>
|
||||
<input
|
||||
id="emailInput"
|
||||
v-model="email"
|
||||
class="form-control"
|
||||
type="email"
|
||||
:required="true"
|
||||
:placeholder="$t('reportEmailPlaceholder')"
|
||||
:class="{'input-invalid': emailInvalid, 'input-valid': emailValid}"
|
||||
>
|
||||
|
||||
<div class="error-label mt-2" v-if="emailInvalid">
|
||||
{{ $t('reportEmailError') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label v-once>
|
||||
{{ $t('reportDescription') }}
|
||||
</label>
|
||||
<div class="mb-2 description-label" v-once>
|
||||
{{ $t('reportDescriptionText') }}
|
||||
</div>
|
||||
<textarea
|
||||
v-model="message"
|
||||
class="form-control"
|
||||
rows="5"
|
||||
:required="true"
|
||||
:placeholder="$t('reportDescriptionPlaceholder')"
|
||||
:class="{'input-invalid': messageInvalid && this.message.length === 0}"
|
||||
>
|
||||
|
||||
</textarea>
|
||||
|
||||
<button
|
||||
class="btn btn-primary submit-button btn-block mx-auto mt-4"
|
||||
type="submit"
|
||||
:disabled="!message || !emailValid"
|
||||
>
|
||||
{{ $t('submitBugReport') }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a
|
||||
class="cancel-link mx-auto mb-4"
|
||||
@click.prevent="close()"
|
||||
>
|
||||
{{ $t('cancel') }}
|
||||
</a>
|
||||
</div>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
#bug-report-modal {
|
||||
.modal-header {
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.modal-dialog {
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding-top: 1rem;
|
||||
padding-right: 1.5rem;
|
||||
padding-left: 1.5rem;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
border-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
h2 {
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.bug-report-modal-header {
|
||||
color: $white;
|
||||
width: 100%;
|
||||
padding: 2rem 3rem 1.5rem 1.5rem;
|
||||
|
||||
background-image: linear-gradient(288deg, #{$purple-200}, #{$purple-300});
|
||||
}
|
||||
|
||||
.report-bug-header-describe {
|
||||
font-size: 14px;
|
||||
line-height: 1.71;
|
||||
color: $purple-600;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
line-height: 1.71;
|
||||
color: $gray-50;
|
||||
}
|
||||
|
||||
.cancel-link {
|
||||
color: $blue-10;
|
||||
line-height: 1.71;
|
||||
}
|
||||
|
||||
.submit-button {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.error-label {
|
||||
font-size: 12px;
|
||||
line-height: 1.33;
|
||||
color: $maroon-10;
|
||||
}
|
||||
|
||||
.description-label {
|
||||
font-size: 12px;
|
||||
line-height: 1.33;
|
||||
color: $gray-100;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import isEmail from 'validator/lib/isEmail';
|
||||
import closeIcon from '@/components/shared/closeIcon';
|
||||
import { mapState } from '@/libs/store';
|
||||
import { MODALS } from '@/libs/consts';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
closeIcon,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
message: '',
|
||||
email: '',
|
||||
messageInvalid: false,
|
||||
modalId: MODALS.BUG_REPORT,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async sendBugReport () {
|
||||
this.messageInvalid = false;
|
||||
|
||||
if (this.message.length === 0) {
|
||||
this.messageInvalid = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await axios.post('/api/v4/bug-report', {
|
||||
message: this.message,
|
||||
email: this.email,
|
||||
});
|
||||
|
||||
this.message = '';
|
||||
|
||||
this.close();
|
||||
|
||||
this.$root.$emit('bv::show::modal', MODALS.BUG_REPORT_SUCCESS);
|
||||
},
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', MODALS.BUG_REPORT);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
emailValid () {
|
||||
if (this.email.length <= 3) return false;
|
||||
return isEmail(this.email);
|
||||
},
|
||||
emailInvalid () {
|
||||
if (this.email.length <= 3) return false;
|
||||
return !this.emailValid;
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
const { user } = this;
|
||||
|
||||
let email = user.auth?.local?.email;
|
||||
|
||||
if (!email && user.auth?.facebook?.emails) {
|
||||
email = user.auth.facebook.emails?.[0]?.value;
|
||||
}
|
||||
|
||||
if (!email && user.auth?.google?.emails) {
|
||||
email = user.auth.google.emails?.[0]?.value;
|
||||
}
|
||||
|
||||
if (!email && user.auth?.apple?.emails) {
|
||||
email = user.auth.apple.emails?.[0]?.value;
|
||||
}
|
||||
|
||||
this.email = email;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user