Skip to content

Commit

Permalink
FIO-7899: fixed an issue where saveDraft option does not work and add…
Browse files Browse the repository at this point in the history
…ed errors handling for the save draft and restore draft functionality (#5521)

* FIO-7899: fixed an issue where saveDraft option does not work and added errors handling for the save draft and restore draft functionality

* FIO-7899 add yarn.lock

* FIO-7899 point yarn.lock to correct registry

* FIO-7899 Update choices yarn.lock to yarn registry

* FIO-7899 Override all pkg.form.io entries to yarnpkg.com

---------

Co-authored-by: lane-formio <[email protected]>
  • Loading branch information
TanyaGashtold and lane-formio authored Mar 6, 2024
1 parent 14ae765 commit 9126f5c
Show file tree
Hide file tree
Showing 3 changed files with 242 additions and 8 deletions.
33 changes: 25 additions & 8 deletions src/Webform.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,13 @@ export default class Webform extends NestedDataComponent {

// See if we need to restore the draft from a user.
if (this.options.saveDraft && !this.options.skipDraftRestore) {
const user = Formio.getUser();
// Only restore a draft if the submission isn't explicitly set.
if (user && !this.submissionSet) {
this.restoreDraft(user._id);
}
this.formReady.then(()=> {
const user = Formio.getUser();
// Only restore a draft if the submission isn't explicitly set.
if (user && !this.submissionSet) {
this.restoreDraft(user._id);
}
});
}

this.component.clearOnHide = false;
Expand Down Expand Up @@ -746,6 +748,12 @@ export default class Webform extends NestedDataComponent {
);
}

handleDraftError(errName, errDetails, restoreDraft) {
const errorMessage = _.trim(`${this.t(errName)} ${errDetails || ''}`);
console.warn(errorMessage);
this.emit(restoreDraft ? 'restoreDraftError' : 'saveDraftError', errDetails || errorMessage);
}

/**
* Saves a submission draft.
*/
Expand All @@ -754,11 +762,11 @@ export default class Webform extends NestedDataComponent {
return;
}
if (!this.formio) {
console.warn(this.t('saveDraftInstanceError'));
this.handleDraftError('saveDraftInstanceError');
return;
}
if (!Formio.getUser()) {
console.warn(this.t('saveDraftAuthError'));
this.handleDraftError('saveDraftAuthError');
return;
}
const draft = fastCloneDeep(this.submission);
Expand All @@ -772,6 +780,10 @@ export default class Webform extends NestedDataComponent {
this.submission._id = sub._id;
this.savingDraft = false;
this.emit('saveDraft', sub);
})
.catch(err => {
this.savingDraft = false;
this.handleDraftError('saveDraftError', err);
});
}
}
Expand All @@ -783,7 +795,7 @@ export default class Webform extends NestedDataComponent {
*/
restoreDraft(userId) {
if (!this.formio) {
console.warn(this.t('restoreDraftInstanceError'));
this.handleDraftError('restoreDraftInstanceError', null, true);
return;
}
this.savingDraft = true;
Expand All @@ -805,6 +817,11 @@ export default class Webform extends NestedDataComponent {
this.draftEnabled = true;
this.savingDraft = false;
this.emit('restoreDraft', null);
})
.catch(err => {
this.draftEnabled = true;
this.savingDraft = false;
this.handleDraftError('restoreDraftError', err, true);
});
}

Expand Down
215 changes: 215 additions & 0 deletions src/Webform.unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4583,6 +4583,221 @@ describe('Webform tests', function() {
});
});

describe('SaveDraft functionality', () => {
const originalMakeRequest = Formio.makeRequest;
let saveDraftCalls = 0;
let restoreDraftCalls = 0;
const scenario = {
restoreDraftError: false,
saveDraftError: false,
};
const restoredDraftData = {
textField: 'test',
number: 1234,
textArea: 'test',
submit: false,
};

before((done) => {
Formio.setUser({
_id: '123'
});

Formio.makeRequest = (formio, type, url, method, data) => {
if (type === 'submission' && method === 'put') {
saveDraftCalls = ++saveDraftCalls;
return scenario.saveDraftError
? Promise.reject('Save Draft Error')
: Promise.resolve(fastCloneDeep(data));
}
if (type === 'form' && method === 'get') {
return Promise.resolve(fastCloneDeep({
_id: '65cdd69efb1b9683c216fa1d',
title: 'test draft errors',
name: 'testDraftErrors',
path: 'testdrafterrors',
type: 'form',
display: 'form',
components: [
{
label: 'Text Field',
applyMaskOn: 'change',
tableView: true,
validate: {
required: true,
},
key: 'textField',
type: 'textfield',
input: true,
},
{
label: 'Number',
applyMaskOn: 'change',
mask: false,
tableView: false,
delimiter: false,
requireDecimal: false,
inputFormat: 'plain',
truncateMultipleSpaces: false,
validate: {
min: 800,
},
key: 'number',
type: 'number',
input: true,
},
{
label: 'Text Area',
applyMaskOn: 'change',
autoExpand: false,
tableView: true,
key: 'textArea',
type: 'textarea',
input: true,
},
{
label: 'Submit',
disableOnInvalid: true,
tableView: false,
key: 'submit',
type: 'button',
input: true,
saveOnEnter: false,
},
],
project: '65b0ccbaf019a907ac01a869',
machineName: 'zarbzxibjafpcjb:testDraftErrors',
}));
}

if (type === 'submissions' && method === 'get') {
restoreDraftCalls = ++restoreDraftCalls;
return scenario.restoreDraftError
? Promise.reject('Restore Draft Error')
: Promise.resolve([
fastCloneDeep({
_id: '65d31f8da08cff1b9fc35966',
form: '65cdd69efb1b9683c216fa1d',
owner: '637b2e6b48c1227e60b1f910',
data: restoredDraftData,
project: '65b0ccbaf019a907ac01a869',
state: 'draft',
}),
]);
}
};

done();
});

afterEach(() => {
saveDraftCalls = 0;
restoreDraftCalls = 0;
scenario.restoreDraftError = false;
scenario.saveDraftError = false;
});

after((done) => {
Formio.makeRequest = originalMakeRequest;
Formio.setUser();
done();
});

it('Should restore draft', function(done) {
const formElement = document.createElement('div');
Formio.createForm(
formElement,
'http://localhost:3000/zarbzxibjafpcjb/testdrafterrors',
{
saveDraft: true
}
).then((form) => {
setTimeout(() => {
assert.equal(restoreDraftCalls, 1);
assert.equal(saveDraftCalls, 0);
assert.equal(form.submission.state, 'draft');
assert.deepEqual(form.data, restoredDraftData);
done();
}, 200);
}).catch((err) => done(err));
});

it('Should save draft after data is changed', function(done) {
const formElement = document.createElement('div');
Formio.createForm(
formElement,
'http://localhost:3000/zarbzxibjafpcjb/testdrafterrors',
{
saveDraft: true
}
).then((form) => {
setTimeout(() => {
assert.equal(restoreDraftCalls, 1);
assert.equal(saveDraftCalls, 0);
assert.equal(form.submission.state, 'draft');
const tfInput = form.getComponent('textField').refs.input[0];
tfInput.value = 'test resaved';
const inputEvent = new Event('input');
tfInput.dispatchEvent(inputEvent);
setTimeout(() => {
assert.equal(restoreDraftCalls, 1);
assert.equal(saveDraftCalls, 1);
assert.equal(form.submission.state, 'draft');
done();
}, 300);
}, 200);
}).catch((err) => done(err));
});

it('Should emit restoreDraftEvent on the restore draft error', function(done) {
const formElement = document.createElement('div');
Formio.createForm(
formElement,
'http://localhost:3000/zarbzxibjafpcjb/testdrafterrors',
{
saveDraft: true
}
).then((form) => {
scenario.restoreDraftError = true;
form.on('restoreDraftError', (err) => {
assert.equal(err, 'Restore Draft Error');
assert.equal(restoreDraftCalls, 1);
assert.equal(saveDraftCalls, 0);
done();
});
}).catch((err) => done(err));
});

it('Should emit saveDraftEvent on the save draft error', function(done) {
const formElement = document.createElement('div');
Formio.createForm(
formElement,
'http://localhost:3000/zarbzxibjafpcjb/testdrafterrors',
{
saveDraft: true
}
).then((form) => {
scenario.saveDraftError = true;
form.on('saveDraftError', (err) => {
assert.equal(err, 'Save Draft Error');
assert.equal(saveDraftCalls, 1);
assert.equal(restoreDraftCalls, 1);
assert.equal(form.submission.state, 'draft');
done();
});

setTimeout(() => {
assert.equal(saveDraftCalls, 0);
assert.equal(restoreDraftCalls, 1);
const tfInput = form.getComponent('textField').refs.input[0];
tfInput.value = 'test resaved';
const inputEvent = new Event('input');
tfInput.dispatchEvent(inputEvent);
}, 200);
}).catch((err) => done(err));
});
});

for (const formTest of FormTests) {
const useDoneInsteadOfPromise = formTest.useDone;

Expand Down
2 changes: 2 additions & 0 deletions src/translations/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ export default {
saveDraftInstanceError: 'Cannot save draft because there is no formio instance.',
saveDraftAuthError: 'Cannot save draft unless a user is authenticated.',
restoreDraftInstanceError: 'Cannot restore draft because there is no formio instance.',
saveDraftError: 'Unable to save draft.',
restoreDraftError: 'Unable to restore draft.',
time: 'Invalid time',
cancelButtonAriaLabel: 'Cancel button. Click to reset the form',
previousButtonAriaLabel:'Previous button. Click to go back to the previous tab',
Expand Down

0 comments on commit 9126f5c

Please sign in to comment.