Skip to content

Commit 645c2b7

Browse files
Stub Survey picker modal for Import unused sample
We still have to show the unused respondents count, and maybe fix the style a bit. There's also some error handling left before finishing the feature. See #2389 See #2390
1 parent 56ed55f commit 645c2b7

9 files changed

Lines changed: 75 additions & 8 deletions

File tree

assets/js/components/surveys/RespondentsDropzone.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import React, { PropTypes } from "react"
22
import Dropzone from "react-dropzone"
33
import { Preloader } from "react-materialize"
44

5-
export const RespondentsDropzone = ({ survey, uploading, onDrop, onDropRejected }) => {
5+
export const RespondentsDropzone = ({ survey, uploading, importing, onDrop, onDropRejected }) => {
66
let className = "drop-text csv"
77
if (uploading) className += " uploading"
8+
if (importing) className += " importing"
89

910
let icon = null
1011
if (uploading) {
@@ -53,6 +54,7 @@ export const dropzoneProps = () => {
5354
RespondentsDropzone.propTypes = {
5455
survey: PropTypes.object,
5556
uploading: PropTypes.bool,
57+
importing: PropTypes.bool,
5658
onDrop: PropTypes.func.isRequired,
5759
onDropRejected: PropTypes.func.isRequired,
5860
}

assets/js/components/surveys/SurveyEdit.jsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class SurveyEdit extends Component {
1515
t: PropTypes.func,
1616
dispatch: PropTypes.func,
1717
projectId: PropTypes.any.isRequired,
18+
projectSurveys: PropTypes.object,
1819
surveyId: PropTypes.any.isRequired,
1920
router: PropTypes.object.isRequired,
2021
survey: PropTypes.object.isRequired,
@@ -23,6 +24,7 @@ class SurveyEdit extends Component {
2324
project: PropTypes.object,
2425
respondentGroups: PropTypes.object,
2526
respondentGroupsUploading: PropTypes.bool,
27+
respondentGroupsImporting: PropTypes.bool,
2628
respondentGroupsUploadingExisting: PropTypes.object,
2729
invalidRespondents: PropTypes.object,
2830
invalidGroup: PropTypes.bool,
@@ -55,11 +57,13 @@ class SurveyEdit extends Component {
5557
survey,
5658
projectId,
5759
project,
60+
projectSurveys,
5861
questionnaires,
5962
dispatch,
6063
channels,
6164
respondentGroups,
6265
respondentGroupsUploading,
66+
respondentGroupsImporting,
6367
respondentGroupsUploadingExisting,
6468
invalidRespondents,
6569
invalidGroup,
@@ -90,10 +94,12 @@ class SurveyEdit extends Component {
9094
survey={survey}
9195
respondentGroups={respondentGroups}
9296
respondentGroupsUploading={respondentGroupsUploading}
97+
respondentGroupsImporting={respondentGroupsImporting}
9398
respondentGroupsUploadingExisting={respondentGroupsUploadingExisting}
9499
invalidRespondents={invalidRespondents}
95100
invalidGroup={invalidGroup}
96101
projectId={projectId}
102+
projectSurveys={projectSurveys}
97103
questionnaires={activeQuestionnaires}
98104
channels={channels}
99105
dispatch={dispatch}
@@ -108,11 +114,13 @@ class SurveyEdit extends Component {
108114
const mapStateToProps = (state, ownProps) => ({
109115
projectId: ownProps.params.projectId,
110116
project: state.project.data,
117+
projectSurveys: state.surveys.items,
111118
surveyId: ownProps.params.surveyId,
112119
channels: state.channels.items,
113120
questionnaires: state.questionnaires.items || {},
114121
respondentGroups: state.respondentGroups.items || {},
115122
respondentGroupsUploading: state.respondentGroups.uploading,
123+
respondentGroupsImporting: state.respondentGroups.importing,
116124
respondentGroupsUploadingExisting: state.respondentGroups.uploadingExisting,
117125
invalidRespondents: state.respondentGroups.invalidRespondents,
118126
invalidGroup: state.respondentGroups.invalidRespondentsForGroup,

assets/js/components/surveys/SurveyForm.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ class SurveyForm extends Component {
2424
t: PropTypes.func,
2525
dispatch: PropTypes.func,
2626
projectId: PropTypes.any.isRequired,
27+
projectSurveys: PropTypes.object,
2728
survey: PropTypes.object.isRequired,
2829
surveyId: PropTypes.any.isRequired,
2930
router: PropTypes.object.isRequired,
3031
questionnaires: PropTypes.object,
3132
questionnaire: PropTypes.object,
3233
respondentGroups: PropTypes.object,
3334
respondentGroupsUploading: PropTypes.bool,
35+
respondentGroupsImporting: PropTypes.bool,
3436
respondentGroupsUploadingExisting: PropTypes.object,
3537
invalidRespondents: PropTypes.object,
3638
invalidGroup: PropTypes.bool,
@@ -89,10 +91,12 @@ class SurveyForm extends Component {
8991
const {
9092
survey,
9193
projectId,
94+
projectSurveys,
9295
questionnaires,
9396
channels,
9497
respondentGroups,
9598
respondentGroupsUploading,
99+
respondentGroupsImporting,
96100
respondentGroupsUploadingExisting,
97101
invalidRespondents,
98102
invalidGroup,
@@ -308,9 +312,11 @@ class SurveyForm extends Component {
308312
<SurveyWizardRespondentsStep
309313
projectId={projectId}
310314
survey={survey}
315+
projectSurveys={projectSurveys}
311316
channels={channels}
312317
respondentGroups={respondentGroups}
313318
respondentGroupsUploading={respondentGroupsUploading}
319+
respondentGroupsImporting={respondentGroupsImporting}
314320
respondentGroupsUploadingExisting={respondentGroupsUploadingExisting}
315321
invalidRespondents={invalidRespondents}
316322
invalidGroup={invalidGroup}

assets/js/components/surveys/SurveySettings.jsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class SurveySettings extends Component {
1414
t: PropTypes.func,
1515
dispatch: PropTypes.func,
1616
projectId: PropTypes.any.isRequired,
17+
projectSurveys: PropTypes.object,
1718
surveyId: PropTypes.any.isRequired,
1819
router: PropTypes.object.isRequired,
1920
survey: PropTypes.object.isRequired,
@@ -22,6 +23,7 @@ class SurveySettings extends Component {
2223
project: PropTypes.object,
2324
respondentGroups: PropTypes.object,
2425
respondentGroupsUploading: PropTypes.bool,
26+
respondentGroupsImporting: PropTypes.bool,
2527
respondentGroupsUploadingExisting: PropTypes.object,
2628
invalidRespondents: PropTypes.object,
2729
invalidGroup: PropTypes.bool,
@@ -44,11 +46,13 @@ class SurveySettings extends Component {
4446
survey,
4547
projectId,
4648
project,
49+
projectSurveys,
4750
questionnaires,
4851
dispatch,
4952
channels,
5053
respondentGroups,
5154
respondentGroupsUploading,
55+
respondentGroupsImporting,
5256
respondentGroupsUploadingExisting,
5357
invalidRespondents,
5458
invalidGroup,
@@ -73,10 +77,12 @@ class SurveySettings extends Component {
7377
survey={survey}
7478
respondentGroups={respondentGroups}
7579
respondentGroupsUploading={respondentGroupsUploading}
80+
respondentGroupsImporting={respondentGroupsImporting}
7681
respondentGroupsUploadingExisting={respondentGroupsUploadingExisting}
7782
invalidRespondents={invalidRespondents}
7883
invalidGroup={invalidGroup}
7984
projectId={projectId}
85+
projectSurveys={projectSurveys}
8086
questionnaires={questionnaires}
8187
channels={channels}
8288
dispatch={dispatch}
@@ -91,11 +97,13 @@ class SurveySettings extends Component {
9197
const mapStateToProps = (state, ownProps) => ({
9298
projectId: ownProps.params.projectId,
9399
project: state.project.data,
100+
projectSurveys: state.surveys.items,
94101
surveyId: ownProps.params.surveyId,
95102
channels: state.channels.items,
96103
questionnaires: (state.survey.data || {}).questionnaires || state.questionnaires.items || {},
97104
respondentGroups: state.respondentGroups.items || {},
98105
respondentGroupsUploading: state.respondentGroups.uploading,
106+
respondentGroupsImporting: state.respondentGroups.importing,
99107
respondentGroupsUploadingExisting: state.respondentGroups.uploadingExisting,
100108
invalidRespondents: state.respondentGroups.invalidRespondents,
101109
invalidGroup: state.respondentGroups.invalidRespondentsForGroup,

assets/js/components/surveys/SurveyWizardRespondentsStep.jsx

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import { connect } from "react-redux"
44
import { Preloader } from "react-materialize"
55
import { ConfirmationModal, Card } from "../ui"
66
import * as actions from "../../actions/respondentGroups"
7+
import * as surveysActions from "../../actions/surveys"
78
import uniq from "lodash/uniq"
89
import flatten from "lodash/flatten"
10+
import ImportSampleModal from "./ImportSampleModal"
911
import { RespondentsList } from "./RespondentsList"
1012
import { RespondentsDropzone } from "./RespondentsDropzone"
1113
import { RespondentsContainer } from "./RespondentsContainer"
@@ -16,8 +18,10 @@ class SurveyWizardRespondentsStep extends Component {
1618
static propTypes = {
1719
t: PropTypes.func,
1820
survey: PropTypes.object,
21+
projectSurveys: PropTypes.object,
1922
respondentGroups: PropTypes.object.isRequired,
2023
respondentGroupsUploading: PropTypes.bool,
24+
respondentGroupsImporting: PropTypes.bool,
2125
respondentGroupsUploadingExisting: PropTypes.object,
2226
invalidRespondents: PropTypes.object,
2327
invalidGroup: PropTypes.bool,
@@ -32,9 +36,16 @@ class SurveyWizardRespondentsStep extends Component {
3236
if (files.length > 0) actions.uploadRespondentGroup(survey.projectId, survey.id, files)
3337
}
3438

35-
importUnusedSample() {
39+
showImportUnusedSampleModal(e) {
40+
e.preventDefault()
41+
let { projectId, surveysActions} = this.props
42+
surveysActions.fetchSurveys(projectId)
43+
$('#importUnusedSampleModal').modal("open")
44+
}
45+
46+
importUnusedSample(sourceSurveyId) {
3647
const { survey, actions } = this.props
37-
actions.importUnusedSampleFromSurvey(survey.projectId, survey.id, 1) // FIXME: actually pick the source survey ID
48+
actions.importUnusedSampleFromSurvey(survey.projectId, survey.id, sourceSurveyId)
3849
}
3950

4051
addMoreRespondents(groupId, file) {
@@ -329,9 +340,11 @@ class SurveyWizardRespondentsStep extends Component {
329340
render() {
330341
let {
331342
survey,
343+
projectSurveys,
332344
channels,
333345
respondentGroups,
334346
respondentGroupsUploading,
347+
respondentGroupsImporting,
335348
respondentGroupsUploadingExisting,
336349
invalidRespondents,
337350
readOnly,
@@ -348,18 +361,25 @@ class SurveyWizardRespondentsStep extends Component {
348361

349362
let importUnusedSampleButton = <div className="row">
350363
<div className="col s12">
351-
<a key="y" href="#" onClick={() => this.importUnusedSample()} className="btn-flat btn-flat-link">
352-
{t("Import uncontacted respondents from other survey")}
364+
<a key="y" href="#" onClick={this.showImportUnusedSampleModal.bind(this)} className="btn-flat btn-flat-link">
365+
{t("Import unused respondents")}
353366
</a>
354367
</div>
355368
</div>
356369

370+
let importUnusedSampleModal = <ImportSampleModal
371+
projectSurveys={projectSurveys}
372+
onConfirm={this.importUnusedSample.bind(this)}
373+
modalId="importUnusedSampleModal"
374+
/>
375+
357376
let respondentsDropzone = null
358377
if (!readOnly && !surveyStarted) {
359378
respondentsDropzone = (
360379
<RespondentsDropzone
361380
survey={survey}
362381
uploading={respondentGroupsUploading}
382+
importing={respondentGroupsImporting}
363383
onDrop={(file) => this.handleSubmit(file)}
364384
onDropRejected={() => $("#invalidTypeFile").modal("open")}
365385
/>
@@ -400,13 +420,15 @@ class SurveyWizardRespondentsStep extends Component {
400420
/>
401421
{invalidRespondentsCard || respondentsDropzone}
402422
{importUnusedSampleButton}
423+
{importUnusedSampleModal}
403424
</RespondentsContainer>
404425
)
405426
}
406427
}
407428

408429
const mapDispatchToProps = (dispatch) => ({
409430
actions: bindActionCreators(actions, dispatch),
431+
surveysActions: bindActionCreators(surveysActions, dispatch)
410432
})
411433

412434
export default translate()(connect(null, mapDispatchToProps)(SurveyWizardRespondentsStep))

assets/js/components/ui/CardTable.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export const CardTable = ({
1818
tableScroll: tableScroll,
1919
})}
2020
>
21-
<div className="card-table-title">{title}</div>
21+
{ title ? <div className="card-table-title">{title}</div> : null }
2222
<div className="card-table">
2323
<table className={classNames(className, { highlight: highlight })} style={style}>
2424
{children}
@@ -31,7 +31,7 @@ export const CardTable = ({
3131
)
3232

3333
CardTable.propTypes = {
34-
title: PropTypes.node.isRequired,
34+
title: PropTypes.node,
3535
highlight: PropTypes.bool,
3636
tableScroll: PropTypes.bool,
3737
children: PropTypes.node,

assets/js/i18nStyle.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ class I18nStyle extends Component<Props> {
1717
.dropfile .drop-text.csv.uploading:before {
1818
content: '${t("Uploading...")}';
1919
}
20+
.dropfile .drop-text.csv.uploading.importing:before {
21+
content: '${t("Importing...")}';
22+
}
2023
.dropfile .drop-text.audio:before {
2124
content: '${t("Drop your MP3, WAV, M4A, ACC or MP4 file here, or click to browse")}';
2225
}

assets/js/reducers/respondentGroups.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as actions from "../actions/respondentGroups"
33
const initialState = {
44
fetching: false,
55
uploading: false,
6+
importing: false,
67
uploadingExisting: {},
78
items: null,
89
surveyId: null,
@@ -16,6 +17,8 @@ export default (state = initialState, action) => {
1617
return fetchRespondentGroups(state, action)
1718
case actions.UPLOAD_RESPONDENT_GROUP:
1819
return uploadRespondentGroup(state, action)
20+
case actions.IMPORT_RESPONDENTS:
21+
return importRespondentGroup(state, action)
1922
case actions.UPLOAD_EXISTING_RESPONDENT_GROUP_ID:
2023
return uploadExistingRespondentGroup(state, action)
2124
case actions.DONE_UPLOAD_EXISTING_RESPONDENT_GROUP_ID:
@@ -59,6 +62,14 @@ const uploadRespondentGroup = (state, action) => {
5962
}
6063
}
6164

65+
const importRespondentGroup = (state, action) => {
66+
return {
67+
...state,
68+
uploading: true,
69+
importing: true,
70+
}
71+
}
72+
6273
const uploadExistingRespondentGroup = (state, action) => {
6374
return {
6475
...state,
@@ -89,6 +100,7 @@ const receiveRespondentGroups = (state, action) => {
89100
...state,
90101
fetching: false,
91102
uploading: false,
103+
importing: false,
92104
items: respondentGroups,
93105
invalidRespondents: null,
94106
}
@@ -100,6 +112,7 @@ const receiveRespondentGroup = (state, action) => {
100112
...state,
101113
fetching: false,
102114
uploading: false,
115+
importing: false,
103116
items: {
104117
...state.items,
105118
[group.id]: group,
@@ -128,6 +141,7 @@ const clearInvalids = (state, action) => {
128141
...state,
129142
invalidRespondents: null,
130143
uploading: false,
144+
importing: false,
131145
}
132146
}
133147

locales/template/translation.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@
194194
"Generated <i>{{surveyName}}</i> {{reportType}} file": "",
195195
"Ignored Values": "",
196196
"Import questionnaire": "",
197-
"Import uncontacted respondents from other survey": "",
197+
"Import unused respondents": "",
198+
"Importing...": "",
198199
"Incentive download was disabled because respondent ids were uploaded": "",
199200
"Incentives file": "",
200201
"Indicate percentages of all sampled cases that will be allocated to each experimental condition": "",
@@ -469,6 +470,7 @@
469470
"Sun": "",
470471
"Surveda will sync available channels from these providers after user authorization": "",
471472
"Survey": "",
473+
"Survey ID": "",
472474
"Survey results": "",
473475
"Surveys": "",
474476
"Target": "",
@@ -522,6 +524,7 @@
522524
"Untitled questionnaire": "",
523525
"Untitled questionnaire section": "",
524526
"Untitled section": "",
527+
"Unused respondents": "",
525528
"Update": "",
526529
"Updated invitation for {{collaboratorEmail}} from {{oldRole}} to {{newRole}}": "",
527530
"Updated membership for {{collaboratorName}} from {{oldRole}} to {{newRole}}": "",
@@ -557,6 +560,7 @@
557560
"Write your message here": "",
558561
"Yes": "",
559562
"You are about to delete all the waves of this panel survey.": "",
563+
"You can import the respondents that haven't been contacted in finished surveys of the project": "",
560564
"You have no active projects": "",
561565
"You have no active questionnaires on this project": "",
562566
"You have no channels on this project": "",

0 commit comments

Comments
 (0)