TT#34950 Add attachment option to send fax feature

What has been done:
- TT#43261, Implement API method for sending fax attachment
- TT#43260, Extend form to also include attachment selection
- TT#43262, Implement method and state handling for attachment selection
  field
- TT#43263, Implement UI flow for sending content or attachment, or both
  if possible

Change-Id: I09b20005c1647f9773f9c7dcb2f141f8c9420d5b
changes/19/23219/8
raxelsen 7 years ago committed by Hans-Peter Herzog
parent 7e432852fa
commit 5f1133a150

@ -67,7 +67,6 @@ For outgoing you need to use the api (also with E 164 number set to sms number f
username: ''
`
1. Apply the exim configuration changes via `sudo ngcpcfg apply 'adjust exim4 / MTA configuration'`
1. For the rest of the prompts, press enter to choose the defaults
1. Go to Settings > Subscribers, find subscriber you want to use as caller, and click "Details"
1. Under "Master Data" click edit, and enter subscribers number also in the E164 field
1. Then go to "Preferences", and set "Fax2Mail and Sendfax" to active

@ -1,14 +1,18 @@
import _ from 'lodash';
import Vue from 'vue';
export function createFax(options, subscriberId) {
export function createFax(options) {
return new Promise((resolve, reject) => {
let headers = {
'Content-Type': 'application/json',
};
let mergedParams = Object.assign(options, subscriberId);
let payload = JSON.stringify(mergedParams);
Vue.http.post('api/faxes/', payload, { headers: headers }).then(() => {
var formData = new FormData();
var fields = _.clone(options);
delete fields.file;
var json = JSON.stringify(fields);
formData.append('json', json);
if (options.file) {
formData.append('faxfile', options.file);
}
Vue.http.post('api/faxes/', formData).then(() => {
resolve();
}).catch((err)=>{
reject(err);

@ -7,55 +7,139 @@
<div class="title">
{{ $t('communication.sendFax') }}
</div>
<q-field>
<q-field :error-label="destinationErrorMessage">
<q-input
clearable
type="text"
v-model="form.destination"
:float-label="$t('communication.label.destination')" />
:float-label="$t('communication.label.destination')"
@input="$v.form.destination.$touch"
@blur="$v.form.destination.$touch"
:error="$v.form.destination.$error"
/>
</q-field>
<q-field>
<q-select
v-model="form.quality"
:options="qualityOptions"
:float-label="$t('communication.label.quality')" />
:float-label="$t('communication.label.quality')"
/>
</q-field>
<q-field>
<q-field :error-label="pageHeaderErrorMessage">
<q-input
clearable
type="text"
v-model="form.pageheader"
:float-label="$t('communication.label.pageHeader')" />
v-model="form.pageHeader"
:float-label="$t('communication.label.pageHeader')"
@input="$v.form.pageHeader.$touch"
@blur="$v.form.pageHeader.$touch"
:error="$v.form.pageHeader.$error"
/>
</q-field>
<q-field>
<q-field :error-label="dataErrorMessage">
<q-input
clearable
type="textarea"
:max-height="100"
:min-rows="10"
v-model="form.data"
:float-label="$t('communication.label.content')" />
:float-label="$t('communication.label.content')"
@input="$v.form.data.$touch"
@blur="$v.form.data.$touch"
:error="$v.form.data.$error"
/>
</q-field>
<q-field class="upload-field">
<label
for="file-upload"
class="upload-label"
>
<div class="upload-label">
{{ $t('communication.label.faxFile') }}
</div>
<q-btn
class="upload-button"
flat
dark
@click="$refs.upload.click()"
icon-right="cloud_upload"
>
{{ $t('communication.label.uploadFile') }}
</q-btn>
<span class="upload-filename">
{{ selectedFile }}
</span>
<q-btn
class="reset-button"
v-if="selectedFile.length > 0"
flat
dark
@click="resetFile"
icon-right="cancel"
/>
</label>
<input
ref="upload"
id="file-upload"
type="file"
accept=".pdf,.tiff,.txt,.ps"
@change="processFile($event)"
@input="$v.form.file.$touch"
@blur="$v.form.file.$touch"
:error="$v.form.file.$error"
/>
</q-field>
<q-btn flat dark @click="hideModal">{{ $t('communication.cancel') }}</q-btn>
<q-btn flat color="primary" @click="sendFax" icon-right="insert drive file" :disable="formDisabled">{{ $t('communication.send') }}</q-btn>
<div
v-if="$v.form.file.$error"
id="csc-error-label"
>
{{ fileErrorMessage }}
</div>
<q-btn
flat
dark
@click="hideModal"
>
{{ $t('communication.cancel') }}
</q-btn>
<q-btn
flat
color="primary"
@click="sendFax"
icon-right="insert drive file"
:disable="formDisabled"
>
{{ $t('communication.send') }}
</q-btn>
</q-modal>
</template>
<script>
import {
required,
requiredUnless,
maxLength
} from 'vuelidate/lib/validators'
import {
QModal,
QBtn,
QField,
QSelect,
QInput,
QIcon
} from 'quasar-framework'
export default {
name: 'csc-send-fax',
data () {
return {
showFaxModal: false,
selectedFile: '',
form: {
destination: null,
pageheader: null,
pageHeader: null,
data: null,
quality: 'normal'
quality: 'normal',
file: null
},
qualityOptions: [
{ label: this.$t('communication.quality.normal'), value: 'normal' },
@ -70,26 +154,114 @@
QBtn,
QField,
QSelect,
QInput
QInput,
QIcon
},
validations: {
form: {
destination: {
required,
maxLength: maxLength(64)
},
data: {
required: requiredUnless(function() {
return this.hasContentToSend;
}),
maxLength: maxLength(3600)
},
file: {
required: requiredUnless(function() {
return this.hasContentToSend;
})
},
pageHeader: {
maxLength: maxLength(64)
}
}
},
computed: {
hasContentToSend() {
return (!!this.form.data || !!this.form.file) || !this.$v.form.$anyDirty;
},
formDisabled() {
return !(this.form.destination &&
this.form.data && this.form.quality) ? true : false;
return !this.$v.form.$anyDirty ||
this.$v.form.destination.$error ||
this.$v.form.pageHeader.$error ||
!this.hasContentToSend;
},
destinationErrorMessage() {
if (!this.$v.form.destination.required) {
return this.$t('validationErrors.fieldRequired', {
field: this.$t('communication.label.destination')
});
}
else if (!this.$v.form.destination.maxLength) {
return this.$t('validationErrors.maxLength', {
field: this.$t('communication.label.destination'),
maxLength: this.$v.form.destination.$params.maxLength.max
});
}
},
pageHeaderErrorMessage() {
return this.$t('validationErrors.maxLength', {
field: this.$t('communication.label.pageHeader'),
maxLength: this.$v.form.pageHeader.$params.maxLength.max
});
},
dataErrorMessage() {
if (!this.$v.form.data.required) {
return this.$t('validationErrors.fieldRequiredXor', {
fieldOne: this.$t('communication.label.content'),
fieldTwo: this.$t('communication.label.file')
});
}
else if (!this.$v.form.data.maxLength) {
return this.$t('validationErrors.maxLength', {
field: this.$t('communication.label.content'),
maxLength: this.$v.form.data.$params.maxLength.max
});
}
},
fileErrorMessage() {
return this.$t('validationErrors.fieldRequiredXor', {
fieldOne: this.$t('communication.label.file'),
fieldTwo: this.$t('communication.label.content')
});
}
},
methods: {
resetFile() {
this.form.file = null;
this.selectedFile = '';
},
processFile(event) {
let file = event.target.files[0];
let fileName = file ? file.name : '';
let fileNameSplit = fileName.split('.');
let extension = fileNameSplit[1] ? fileNameSplit[1] : null;
if (fileName.length > 22 && extension) {
fileName = `${fileName.substring(0, 14)}...${extension}`;
}
else if (fileName.length > 22 && !extension) {
fileName = `${fileName.substring(0, 17)}...`;
}
this.form.file = file;
this.selectedFile = fileName;
},
sendFax() {
this.$store.dispatch('communication/createFax', this.form);
},
showModal() {
this.form = {
destination: null,
pageheader: null,
pageHeader: null,
data: null,
quality: 'normal'
quality: 'normal',
file: null
};
this.selectedFile = '';
this.showFaxModal = true;
this.$v.$reset();
},
hideModal() {
this.showFaxModal = false;
@ -112,4 +284,34 @@
line-height $csc-subtitle-line-height
font-size $csc-subtitle-font-size
font-weight $csc-subtitle-font-weight
.upload-field
margin-bottom 10px
.upload-label
display block
color $csc-label
font-size 16px
margin-bottom 5px
.upload-button
color black
.reset-button
padding 0
.q-icon
margin 0
.upload-filename
color black
#file-upload
display none
#csc-error-label
font-size 12px
color $negative
margin -15px 0 10px 0
</style>

@ -32,7 +32,8 @@
"maxValueSecond": "{field} must be maximum of {maxValue} seconds",
"alphaNum": "{field} must consist of numeric characters only",
"inputNumber": "Input a phone number",
"inputValidNumber": "Input a valid phone number"
"inputValidNumber": "Input a valid phone number",
"fieldRequiredXor": "{fieldOne} or {fieldTwo} is required"
},
"navigation": {
"home": {
@ -394,7 +395,10 @@
"destination": "Destination Number",
"quality": "Quality",
"pageHeader": "Page Header",
"content": "Content"
"content": "Content",
"file": "File",
"faxFile": "Fax File",
"uploadFile": "Upload File"
},
"send": "Send",
"cancel": "Cancel",

@ -36,7 +36,7 @@ Vue.http.interceptors.push(function(request, next) {
if(!_.isEmpty(jwt)) {
request.headers.set('Authorization', 'Bearer ' + jwt);
}
if(request.method === 'POST' && _.isEmpty(request.body)) {
if(request.method === 'POST' && (request.body === void(0) || request.body === null)) {
request.body = {};
}
next();

@ -38,11 +38,12 @@ export default {
}
},
actions: {
createFax(context, options) {
createFax(context, $options) {
let options = Object.assign($options, {
subscriber_id: context.getters.subscriberId
});
context.commit('createFaxRequesting');
createFax(options, {
subscriber_id: context.getters.subscriberId
}).then(() => {
createFax(options).then(() => {
context.commit('createFaxSucceeded');
}).catch((err) => {
context.commit('createFaxFailed', err.message);

@ -26,6 +26,8 @@ $negative = #DB2828
$info = #31CCEC
$warning = #F2C037
$csc-label = rgba(0,0,0,0.46)
$toolbar-background = $primary
$toolbar-min-height = 60px
@ -40,7 +42,6 @@ $tooltip-background = $primary
$csc-subtitle-font-size = 18px
$csc-subtitle-line-height = 2rem
$csc-subtitle-font-weight = 400
$item-base-color = $primary
$item-highlight-color = alpha($item-base-color, 15%)

Loading…
Cancel
Save