Skip to content

Commit 180ad7d

Browse files
committed
this will partially fix the ECLK#159
1 parent 0d5333e commit 180ad7d

File tree

10 files changed

+278
-45
lines changed

10 files changed

+278
-45
lines changed

client/package-lock.json

Lines changed: 27 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"npm": "^6.10.0",
3131
"prop-types": "^15.7.2",
3232
"react": "^16.12.0",
33+
"react-csv-reader": "^3.0.6",
3334
"react-datepicker": "^2.0.0",
3435
"react-datetime": "^2.16.3",
3536
"react-dom": "^16.12.0",

client/src/components/CandidateProfile/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class TextFields extends React.Component {
9898
// this.refs.btn.setAttribute("disabled", "disabled");
9999
const { index, customProps,getNominationCandidates,candidateMessage } = this.props;
100100
let {jsonSchemaProperties} = this.state;
101-
let candidateKeyValues = { "nominationId" : customProps,
101+
let candidateKeyValues = { "nominationId" : customProps,"from" : "form",
102102
"candidateData":[] };
103103
for (var configItem in data) {
104104
if(jsonSchemaProperties[configItem]){

client/src/components/NominationStep1/NominationStep1.jsx

Lines changed: 142 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,17 @@ import CustomToolbarEdit from "./CustomToolbarEdit";
66
import CustomToolbarDelete from "./CustomToolbarDelete";
77
import PropTypes from "prop-types";
88
import { getNominationCandidates } from '../../modules/nomination/state/NominationAction';
9+
import { candidateMessage } from '../../modules/election/state/ElectionAction';
910
import { connect } from 'react-redux';
1011
import Grid from '@material-ui/core/Grid';
1112
import { de } from 'date-fns/locale';
12-
13+
import { Button } from '@material-ui/core';
14+
import CSVReader from 'react-csv-reader'
15+
import axios from 'axios';
16+
import _ from 'lodash';
17+
import download from 'downloadjs';
18+
import DownloadIcon from '@material-ui/icons/GetApp';
19+
import { API_BASE_URL } from "../../config.js";
1320

1421
const styles = theme => ({
1522
root: {
@@ -46,13 +53,120 @@ class CustomizedTable extends React.Component {
4653
open: true,
4754
nominations: [],
4855
candidateCount: '0',
56+
jsonSchemaProperties: null,
4957
}
5058

5159
}
5260

61+
handleForce = (data, fileInfo) => console.log("ddd",data, fileInfo);
62+
63+
handleSubmit = (data, callback) => {
64+
65+
// first get the keys out of the first sub array:
66+
const keys = data[0];
67+
68+
// then map over the rest of the sub arrays:
69+
const result = data.slice(1).map(function(item) {
70+
71+
// create an object with key names and item values:
72+
const obj = {};
73+
keys.forEach(function(k,i) {
74+
obj[k] = item[i];
75+
});
76+
return obj;
77+
});
78+
79+
const { customProps,getNominationCandidates,candidateMessage } = this.props;
80+
let {jsonSchemaProperties} = this.state;
81+
let candidateKeyValues = { "nominationId" : customProps,
82+
"candidateData":[] };
83+
84+
result.forEach(function(k,i) {
85+
var data2 = k;
86+
for (var configItem in data2) {
87+
if(jsonSchemaProperties[configItem]){
88+
candidateKeyValues.candidateData.push(
89+
{"candidateConfigId" : jsonSchemaProperties[configItem].id,
90+
"value" : data2[configItem]});
91+
}
92+
}
93+
});
94+
95+
var data3 = candidateKeyValues.candidateData,
96+
ids = ['1', '2', '3', '4', '5'],
97+
result4 = data3
98+
.reduce((r, o) => {
99+
let index = r.indices[o.candidateConfigId]++;
100+
r.data3[index] = r.data3[index] || [];
101+
r.data3[index].push(o);
102+
return r;
103+
}, { indices: Object.fromEntries(ids.map(k => [k, 0])), data3: [] })
104+
.data3;
105+
106+
candidateKeyValues.candidateData = result4;
107+
data.forEach((element,i) => {
108+
109+
});
110+
111+
let url = 'nominations/candidates';
112+
113+
const onCloseModal = this.props.onCloseModal;
114+
axios({
115+
method: 'post',
116+
headers: {
117+
'Accept': 'application/json',
118+
'Content-Type': 'application/json',
119+
},
120+
url: url,
121+
data: candidateKeyValues
122+
})
123+
.then(function (response) {
124+
candidateMessage('Candidate Added Sccessfully...');
125+
getNominationCandidates(customProps);
126+
})
127+
.catch(function (e) {
128+
const message = _.get(e, 'response.data.message');
129+
if(message) {
130+
candidateMessage(message);
131+
}
132+
});
133+
};
134+
53135
componentDidMount() {
54-
const { customProps, getNominationCandidates } = this.props;
136+
const { customProps, getNominationCandidates, moduleId } = this.props;
55137
getNominationCandidates(customProps);
138+
139+
axios.get("modules/"+ moduleId +"/candidate-form-config", {}).then(
140+
(response) => {
141+
var properties = {
142+
// TODO: remove following three
143+
"counsilName": { "type": "hidden", "title": "counsilName", "default": "council", "id": 999 },
144+
"electoralDivisionCode": { "type": "hidden", "title": "electoralDivisionCode", "default": "K01", "id": 998 },
145+
"electoralDivisionName": { "type": "hidden", "title": "electoralDivisionName", "default": "kalutara", "id": 997 },
146+
147+
"nominationId": { "type": "hidden", "title": "nominationId", "default": this.props.customProps, "id": 996},
148+
};
149+
150+
const sortedData = _.orderBy(response.data, ['candidate_config_id'], "asc");
151+
var configLength = sortedData.length;
152+
for (var i = 0; i < configLength; i++) {
153+
const config = sortedData[i];
154+
const keyName = config['key_name'];
155+
const schema = config["json_schema"];
156+
if (schema) {
157+
properties[keyName] = JSON.parse(schema);
158+
} else {
159+
properties[keyName] = { "type": "string"};
160+
}
161+
properties[keyName].title = config['description'];
162+
properties[keyName].id = config['candidate_config_id'];
163+
}
164+
let progress = 1;
165+
// if(index) {
166+
// progress = 0.5;
167+
// }
168+
this.setState({ ajaxState: this.state.ajaxState + progress, jsonSchemaProperties: properties});
169+
});
56170
}
57171

58172
handleDrawerOpen = () => {
@@ -63,6 +177,15 @@ class CustomizedTable extends React.Component {
63177
this.setState({ open: false });
64178
};
65179

180+
handleFileDownload = () => {
181+
axios.get(`${API_BASE_URL}/nominations/candidate-template/download`, {responseType: 'blob'}, {
182+
}).then((response) => {
183+
download(new Blob([response.data]), 'candidate_upload_template', "text/csv", response.headers['content-type']);
184+
}).catch(err => {
185+
console.log(err)
186+
});
187+
};
188+
66189
render() {
67190
const { classes, CandidateList } = this.props;
68191
const rows = CandidateList;
@@ -170,9 +293,20 @@ class CustomizedTable extends React.Component {
170293
const options = {
171294
filterType: "dropdown",
172295
responsive: "scroll",
296+
filter: false,
173297
customToolbar: () => {
174298
return (
175-
<CustomToolbar customProps={customProps} modalType="Add" />
299+
<Grid container direction="row" justify="flex-end" spacing={2}>
300+
<Grid item lg={2}>
301+
<CustomToolbar customProps={customProps} modalType="Add" />
302+
</Grid>
303+
{/* <Grid style={{marginTop:15}} item lg={6}>
304+
<DownloadIcon onClick={() => { this.handleFileDownload() }} color="red"/>
305+
</Grid> */}
306+
<Grid style={{marginTop:15}} item lg={6}>
307+
<CSVReader onFileLoaded={this.handleSubmit} />
308+
</Grid>
309+
</Grid>
176310
);
177311
}
178312
};
@@ -189,14 +323,16 @@ class CustomizedTable extends React.Component {
189323
}
190324
}
191325

192-
const mapStateToProps = ({ Nomination }) => {
326+
const mapStateToProps = ({ Nomination,Election }) => {
193327
const { getNominationCandidates } = Nomination;
328+
const moduleId = Election.ElectionTimeLineData.moduleId;
194329
const CandidateList = Nomination.getNominationCandidates;
195-
return { getNominationCandidates, CandidateList };
330+
return { getNominationCandidates, CandidateList,moduleId };
196331
};
197332

198333
const mapActionsToProps = {
199-
getNominationCandidates
334+
getNominationCandidates,
335+
candidateMessage
200336
};
201337

202338
export default connect(mapStateToProps, mapActionsToProps)(withStyles(styles)(CustomizedTable));

server/src/repository/candidate.js

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { DBError } from 'Errors';
22
import { DbConnection } from './dataSource';
33
import { formatQueryToBulkInsert, formatDataToBulkInsert} from './sqlHelper';
4+
const uuidv4 = require('uuid/v4');
45

56

67
const CANDIDATE_BY_NOMINATION_SELECT_QUERY = `SELECT CD.ID AS CANDIDATE_ID,
@@ -179,33 +180,85 @@ const updateNominationStatus = (nominationId,transaction) => {
179180
* save candidate data
180181
* @returns {Promise.<T>}
181182
*/
182-
const saveCandidate = async (candidateId,nominationId,data, transaction) => {
183+
const saveCandidate = async (candidateId,nominationId,data,from, transaction) => {
183184
const params = {candidateId:candidateId};
184-
data = data.map((record) => {
185-
record.nominationId = nominationId;
186-
record.id = candidateId
187-
return record;
188-
});
189-
await DbConnection()
190-
.query(CANDIDATE_DELETE_QUERY,
191-
{
192-
replacements: params,
193-
type: DbConnection().QueryTypes.DELETE,
194-
transaction
195-
}).catch((error) => {
196-
throw new DBError(error);
197-
});
185+
186+
if(candidateId == undefined){
187+
console.log("from",from);
188+
if(from == "form"){
189+
var uuid2 = uuidv4();
190+
data = data.map((record) => {
191+
record.nominationId = nominationId;
192+
record.id = uuid2;
193+
return record;
194+
});
195+
}else{
196+
data = data.map((record) => {
197+
var uuid = uuidv4();
198+
record.map((val) => {
199+
val.id = uuid
200+
val.nominationId = nominationId;
201+
})
202+
return record;
203+
});
204+
}
205+
}else{
206+
data = data.map((record) => {
207+
record.nominationId = nominationId;
208+
record.id = candidateId
209+
return record;
210+
});
211+
}
212+
if(candidateId !== undefined){
213+
await DbConnection()
214+
.query(CANDIDATE_DELETE_QUERY,
215+
{
216+
replacements: params,
217+
type: DbConnection().QueryTypes.DELETE,
218+
transaction
219+
}).catch((error) => {
220+
throw new DBError(error);
221+
});
222+
}
223+
198224
if( data instanceof Array && data.length > 0){
199225
try {
200-
return DbConnection()
201-
.query(formatQueryToBulkInsert(CANDIDATE_DATA_INSERT_BASE_QUERY, data),
202-
{
203-
replacements: formatDataToBulkInsert(data, CANDIDATE_DATA_COLUMN_ORDER),
204-
type: DbConnection().QueryTypes.INSERT,
205-
transaction,
206-
}).catch((error) => {
207-
throw new DBError(error);
208-
});
226+
if(candidateId){
227+
return DbConnection()
228+
.query(formatQueryToBulkInsert(CANDIDATE_DATA_INSERT_BASE_QUERY, data),
229+
{
230+
replacements: formatDataToBulkInsert(data, CANDIDATE_DATA_COLUMN_ORDER),
231+
type: DbConnection().QueryTypes.INSERT,
232+
transaction,
233+
}).catch((error) => {
234+
throw new DBError(error);
235+
});
236+
}else{
237+
if(from == "form"){
238+
return DbConnection()
239+
.query(formatQueryToBulkInsert(CANDIDATE_DATA_INSERT_BASE_QUERY, data),
240+
{
241+
replacements: formatDataToBulkInsert(data, CANDIDATE_DATA_COLUMN_ORDER),
242+
type: DbConnection().QueryTypes.INSERT,
243+
transaction,
244+
}).catch((error) => {
245+
throw new DBError(error);
246+
});
247+
}else{
248+
for(let i=0;i<data.length;i++){
249+
DbConnection()
250+
.query(formatQueryToBulkInsert(CANDIDATE_DATA_INSERT_BASE_QUERY, data[i]),
251+
{
252+
replacements: formatDataToBulkInsert(data[i], CANDIDATE_DATA_COLUMN_ORDER),
253+
type: DbConnection().QueryTypes.INSERT,
254+
transaction,
255+
}).catch((error) => {
256+
throw new DBError(error);
257+
});
258+
}
259+
}
260+
}
261+
209262
}catch (e){
210263
console.log(e);
211264
}

0 commit comments

Comments
 (0)