diff --git a/api/controllers/Candidate.js b/api/controllers/Candidate.js index db08fbb..1b9c81b 100644 --- a/api/controllers/Candidate.js +++ b/api/controllers/Candidate.js @@ -1,177 +1,127 @@ +const _ = require('lodash') + module.exports = function (server) { const Candidate = server.plugins['hapi-shelf'].model('Candidate') const SurveyAnswer = server.plugins['hapi-shelf'].model('SurveyAnswer') - function getCategoryAnswers(surveyResponseId, callback) + function getCandidateMatch(surveyResponseId, callback) { SurveyAnswer - .query(function(answer_builder) { + .query(answer_builder => { + answer_builder.column('survey_response.id as response_id') + answer_builder.column('survey_response.geography_id') answer_builder.column('candidate_answer.candidate_id') - answer_builder.column('question.category_id') - answer_builder.column('question.id as question_id') + answer_builder.column('candidate.candidate_name') + answer_builder.column('candidate_type.id as type_id') + answer_builder.column('candidate_type.type_name ') + answer_builder.column('category.id as category_id') + answer_builder.column('category.category_name') + answer_builder.column('survey_answer.question_id') answer_builder.column('question.question_text') - answer_builder.column('a2.id as candidate_answer_id') - answer_builder.column('a2.answer_label as candidate_answer_label') - answer_builder.column('a1.id as voter_answer_id') - answer_builder.column('a1.answer_label as voter_answer_text') - answer_builder.innerJoin('answer as a1', 'survey_answer.answer_id', 'a1.id') + answer_builder.column('survey_answer.answer_id') + answer_builder.column('a1.answer_value as answer_text') + answer_builder.column('candidate_answer.answer_id as candidate_answer_id') + answer_builder.column('a2.answer_value as candidate_answer_text') + answer_builder.column(server.plugins['hapi-shelf'].knex.raw("case \ + when survey_answer.answer_id = candidate_answer.answer_id \ + then (cast(survey_answer.intensity as numeric(3,2)) + cast(candidate_answer.intensity as numeric(3,2))) / 10 \ + else 0.00 \ + end as score")) answer_builder.innerJoin('question', 'survey_answer.question_id', 'question.id') - answer_builder.innerJoin('answer as a2', 'question.id', 'a2.question_id') - answer_builder.innerJoin('candidate_answer', 'a2.id', 'candidate_answer.answer_id') - answer_builder.where('survey_answer.survey_response_id', surveyResponseId) + answer_builder.innerJoin('category', 'question.category_id', 'category.id') + answer_builder.innerJoin('answer as a1', 'survey_answer.answer_id', 'a1.id') + answer_builder.innerJoin('survey_response', 'survey_answer.survey_response_id', 'survey_response.id') + answer_builder.innerJoin('candidate_answer', 'survey_answer.question_id', 'candidate_answer.question_id') + answer_builder.innerJoin('answer as a2', 'candidate_answer.answer_id', 'a2.id') + answer_builder.innerJoin('candidate_geography', function() { + this.on('candidate_answer.candidate_id', '=', 'candidate_geography.candidate_id') + .andOn('candidate_geography.geography_id', '=', 'survey_response.geography_id') + }) + answer_builder.innerJoin('candidate', 'candidate_answer.candidate_id', 'candidate.id') + answer_builder.innerJoin('candidate_type', 'candidate.candidate_type_id', 'candidate_type.id') + answer_builder.where('survey_response.id', surveyResponseId) }) .fetchAll() .then(answers => { - callback(answers) + formatCandidateMatch(answers, callback) }) } - function getCategoryScores(surveyResponseId, callback) + function formatCandidateMatch(matchArray, callback) { - var score_raw = 'round((sum(cast(survey_answer.intensity as numeric(3,2)))) / cat_scores.score * 100) as category_score' + var responses = _.uniq(matchArray.pluck('responseId')) + var geographies = _.uniq(matchArray.pluck('geographyId')) + var candidates = _.uniq(matchArray.pluck('candidateId')) + var candidateTypes = _.uniq(matchArray.pluck('typeId')) + var categories = _.uniq(matchArray.pluck('categoryId')) - SurveyAnswer - .query(function(cat_builder) { - cat_builder.column('candidate_answer.candidate_id') - cat_builder.column('category.id as category_id') - cat_builder.column('category.category_name') - cat_builder.column(server.plugins['hapi-shelf'].knex.raw(score_raw)) - cat_builder.innerJoin('question', 'survey_answer.question_id', 'question.id') - cat_builder.innerJoin('category', 'question.category_id', 'category.id') - cat_builder.innerJoin('survey_response', 'survey_answer.survey_response_id', 'survey_response.id') - cat_builder.innerJoin('candidate_answer', 'survey_answer.answer_id', 'candidate_answer.answer_id') - cat_builder.innerJoin('candidate_geography', function() { - this.on('candidate_answer.candidate_id', '=', 'candidate_geography.candidate_id') - .andOn('candidate_geography.geography_id', '=', 'survey_response.geography_id') - }) - cat_builder.innerJoin('candidate', 'candidate_answer.candidate_id', 'candidate.id') - cat_builder.join(server.plugins['hapi-shelf'].knex.raw(" \ - (select question.category_id, category.category_name, sum(sa.intensity) as score \ - from survey_answer sa \ - inner join question on sa.question_id = question.id \ - inner join category on question.category_id = category.id \ - where sa.survey_response_id = " + surveyResponseId + " \ - group by question.category_id, category.category_name) as cat_scores on category.id = cat_scores.category_id")) - cat_builder.where('survey_response.id', surveyResponseId) - cat_builder.groupBy('candidate_answer.candidate_id', 'category.id', 'category.category_name', 'cat_scores.score') - }) - .fetchAll() - .then(categories => { - callback(categories) - }) - } + if (responses.length === 1) + { + var output = {} + output.id = responses[0] + output.geographyId = geographies[0] - function formatCandidateMatch(matchArray, categoryArray, answerArray) { - var output = {} - output.id = matchArray[0].attributes.surveyId - output.geographyId = matchArray[0].attributes.geographyId - - output.survey = [] - - matchArray.map(function(match) { - var typeIndex = output.survey.findIndex(type => - type.candidateTypeName === match.attributes.typeName) - - var catIndex = -1 - var answerIndex = -1 - - if(typeIndex === -1) - { - typeIndex = output.survey.push({ - candidateTypeId: match.attributes.typeId, - candidateTypeName: match.attributes.typeName, - candidates: [{ - candidateId: match.attributes.candidateId, - candidateName: match.attributes.candidateName, - compositeMatchScore: match.attributes.compositeScore, - categoryMatchScores: [] - }] - })-1 - - categoryArray.map(function(category) { - if (match.attributes.candidateId === category.attributes.candidateId) + output.survey = candidateTypes.map((typeId) => { + var candidateType = {} + + candidateType.candidateTypeId = typeId + candidateType.candidateTypeName = matchArray.findWhere({'typeId': typeId}).get('typeName') + + candidateType.candidates = candidates.map((candidateId) => { + var candidateList = matchArray.where({'typeId': typeId, 'candidateId': candidateId}) + + if (candidateList) { - catIndex = output.survey[typeIndex].candidates[0].categoryMatchScores.findIndex(candCat => - candCat.categoryId === category.attributes.categoryId) - - if (catIndex === -1) - { - catIndex = output.survey[typeIndex].candidates[0].categoryMatchScores.push({ - categoryId: category.attributes.categoryId, - categoryName: category.attributes.categoryName, - categoryMatch: category.attributes.categoryScore, - questions: [] - })-1 - } - - answerArray.map(function(answer) { - if(match.attributes.candidateId === answer.attributes.candidateId - && category.attributes.categoryId === answer.attributes.categoryId) - { - output.survey[typeIndex].candidates[0].categoryMatchScores[catIndex].questions.push({ - questionId: answer.attributes.questionId, - questionText: answer.attributes.questionText, - candidateAnswerId: answer.attributes.candidateAnswerId, - candidateAnswerLabel: answer.attributes.candidateAnswerLabel, - voterAnswerId: answer.attributes.voterAnswerId, - voterAnswerText: answer.attributes.voterAnswerText - }) - } + var candidate = {} + + candidate.candidateId = candidateId + candidate.candidateName = matchArray.findWhere({'candidateId': candidateId}).get('candidateName') + candidate.compositeMatchScore = Math.round((candidateList.reduce((p, n) => { + return p + parseFloat(n.get('score')) + }, 0.0)*100) / (candidateList.length)) + + candidate.categoryMatchScores = categories.map((categoryId) => { + var categoryList = matchArray.where({'typeId': typeId, + 'categoryId': categoryId, + 'candidateId': candidateId}) + + if (categoryList) + { + var category = {} + + category.categoryId = categoryId + category.categoryName = matchArray.findWhere({'categoryId': categoryId}).get('categoryName') + category.categoryMatch = Math.round((categoryList.reduce((p, n) => { + return p + parseFloat(n.get('score')) + }, 0.0)*100) / categoryList.length) + + category.questions = categoryList.map((item) => { + return { + questionId: item.get('questionId'), + questionText: item.get('questionText'), + candidateAnswerId: item.get('candidateAnswerId'), + candidateAnswerLabel: item.get('candidateAnswerText'), + voterAnswerId: item.get('answerId'), + voterAnswerText: item.get('answerText') + } + }) + + return category + } }) + + return candidate } }) - } else { - var candIndex = output.survey[typeIndex].candidates.findIndex(cand => - cand.candidateId === match.attributes.candidateId) - - if (candIndex === -1) - { - candIndex = output.survey[typeIndex].candidates.push({ - candidateId: match.attributes.candidateId, - candidateName: match.attributes.candidateName, - compositeMatchScore: match.attributes.compositeScore, - categoryMatchScores: [] - })-1 - - categoryArray.map(function(category) { - if (match.attributes.candidateId === category.attributes.candidateId) - { - catIndex = output.survey[typeIndex].candidates[candIndex].categoryMatchScores.findIndex(candCat => - candCat.categoryId === category.attributes.categoryId) - - if (catIndex === -1) - { - catIndex = output.survey[typeIndex].candidates[candIndex].categoryMatchScores.push({ - categoryId: category.attributes.categoryId, - categoryName: category.attributes.categoryName, - categoryMatch: category.attributes.categoryScore, - questions: [] - })-1 - } - - answerArray.map(function(answer) { - if(match.attributes.candidateId === answer.attributes.candidateId - && category.attributes.categoryId === answer.attributes.categoryId) - { - output.survey[typeIndex].candidates[candIndex].categoryMatchScores[catIndex].questions.push({ - questionId: answer.attributes.questionId, - questionText: answer.attributes.questionText, - candidateAnswerId: answer.attributes.candidateAnswerId, - candidateAnswerLabel: answer.attributes.candidateAnswerLabel, - voterAnswerId: answer.attributes.voterAnswerId, - voterAnswerText: answer.attributes.voterAnswerText - }) - } - }) - } - }) - } - } - }) - return(output) + return candidateType + }) + } + + callback(output) } + return [{ method: 'GET', path: '/api/candidate', @@ -199,43 +149,8 @@ module.exports = function (server) { method: 'GET', path: '/api/candidate_match/{survey_response_id}', handler: (request, reply) => { - SurveyAnswer - .query(function(score_builder) { - score_builder.sum('intensity as score'); - score_builder.where('survey_response_id', request.params.survey_response_id) - }) - .fetch() - .then(function(total) { - var score_raw = 'round((sum(cast(survey_answer.intensity as numeric(3,2))) / ' - + total.attributes.score + ') * 100) as composite_score' - - SurveyAnswer - .query(function(match_builder) { - match_builder.column('survey_response.id as survey_id', 'survey_response.geography_id') - match_builder.column('candidate_answer.candidate_id', 'candidate.candidate_name') - match_builder.column('candidate_type.id as type_id', 'candidate_type.type_name') - match_builder.column(server.plugins['hapi-shelf'].knex.raw(score_raw)) - match_builder.innerJoin('survey_response', 'survey_answer.survey_response_id', 'survey_response.id') - match_builder.innerJoin('candidate_answer', 'survey_answer.answer_id', 'candidate_answer.answer_id') - match_builder.innerJoin('candidate_geography', function() { - this.on('candidate_answer.candidate_id', '=', 'candidate_geography.candidate_id') - .andOn('candidate_geography.geography_id', '=', 'survey_response.geography_id') - }) - match_builder.innerJoin('candidate', 'candidate_answer.candidate_id', 'candidate.id') - match_builder.innerJoin('candidate_type', 'candidate.candidate_type_id', 'candidate_type.id') - match_builder.where('survey_response.id', request.params.survey_response_id) - match_builder.groupBy('survey_response.id', 'survey_response.geography_id' - , 'candidate_answer.candidate_id', 'candidate.candidate_name' - , 'candidate_type.id', 'candidate_type.type_name') - }) - .fetchAll() - .then(matches => { - getCategoryScores(request.params.survey_response_id, function(categories) { - getCategoryAnswers(request.params.survey_response_id, function(answers) { - reply(formatCandidateMatch(matches.models, categories.models, answers.models)) - }) - }) - }) + getCandidateMatch(request.params.survey_response_id, (matches) => { + reply(matches) }) } }] diff --git a/assets/img/candidates/alexander.jpg b/assets/img/candidates/alexander.jpg new file mode 100644 index 0000000..0827574 Binary files /dev/null and b/assets/img/candidates/alexander.jpg differ diff --git a/assets/img/candidates/candela.jpg b/assets/img/candidates/candela.jpg new file mode 100644 index 0000000..8cbd208 Binary files /dev/null and b/assets/img/candidates/candela.jpg differ diff --git a/assets/img/candidates/cook.jpg b/assets/img/candidates/cook.jpg new file mode 100644 index 0000000..f656b0c Binary files /dev/null and b/assets/img/candidates/cook.jpg differ diff --git a/assets/img/candidates/graves.jpg b/assets/img/candidates/graves.jpg new file mode 100644 index 0000000..d9fd04c Binary files /dev/null and b/assets/img/candidates/graves.jpg differ diff --git a/assets/img/candidates/mccabe.jpg b/assets/img/candidates/mccabe.jpg new file mode 100644 index 0000000..bfc9be0 Binary files /dev/null and b/assets/img/candidates/mccabe.jpg differ diff --git a/assets/img/candidates/mcclellan.jpg b/assets/img/candidates/mcclellan.jpg new file mode 100644 index 0000000..690eb8b Binary files /dev/null and b/assets/img/candidates/mcclellan.jpg differ diff --git a/assets/img/candidates/originals/alexander.png b/assets/img/candidates/originals/alexander.png new file mode 100644 index 0000000..5ea0d99 Binary files /dev/null and b/assets/img/candidates/originals/alexander.png differ diff --git a/assets/img/candidates/originals/billy.png b/assets/img/candidates/originals/billy.png new file mode 100644 index 0000000..77b5600 Binary files /dev/null and b/assets/img/candidates/originals/billy.png differ diff --git a/assets/img/candidates/originals/candela.jpg b/assets/img/candidates/originals/candela.jpg new file mode 100644 index 0000000..4ac445f Binary files /dev/null and b/assets/img/candidates/originals/candela.jpg differ diff --git a/assets/img/candidates/originals/graves.jpg b/assets/img/candidates/originals/graves.jpg new file mode 100644 index 0000000..4300d43 Binary files /dev/null and b/assets/img/candidates/originals/graves.jpg differ diff --git a/assets/img/candidates/originals/mccabe.jpg b/assets/img/candidates/originals/mccabe.jpg new file mode 100644 index 0000000..259b087 Binary files /dev/null and b/assets/img/candidates/originals/mccabe.jpg differ diff --git a/assets/img/candidates/originals/mcclellan.png b/assets/img/candidates/originals/mcclellan.png new file mode 100644 index 0000000..5450df8 Binary files /dev/null and b/assets/img/candidates/originals/mcclellan.png differ diff --git a/assets/img/candidates/originals/protogyrou.jpg b/assets/img/candidates/originals/protogyrou.jpg new file mode 100644 index 0000000..dee32e8 Binary files /dev/null and b/assets/img/candidates/originals/protogyrou.jpg differ diff --git a/assets/img/candidates/originals/stewart.jpg b/assets/img/candidates/originals/stewart.jpg new file mode 100644 index 0000000..ebb047c Binary files /dev/null and b/assets/img/candidates/originals/stewart.jpg differ diff --git a/assets/img/candidates/originals/turner.jpg b/assets/img/candidates/originals/turner.jpg new file mode 100644 index 0000000..21316a8 Binary files /dev/null and b/assets/img/candidates/originals/turner.jpg differ diff --git a/assets/img/candidates/originals/winn.png b/assets/img/candidates/originals/winn.png new file mode 100644 index 0000000..8f4e749 Binary files /dev/null and b/assets/img/candidates/originals/winn.png differ diff --git a/assets/img/candidates/protogyrou.jpg b/assets/img/candidates/protogyrou.jpg new file mode 100644 index 0000000..2ecc9d8 Binary files /dev/null and b/assets/img/candidates/protogyrou.jpg differ diff --git a/assets/img/candidates/stewart.jpg b/assets/img/candidates/stewart.jpg new file mode 100644 index 0000000..aafcd5f Binary files /dev/null and b/assets/img/candidates/stewart.jpg differ diff --git a/assets/img/candidates/turner.jpg b/assets/img/candidates/turner.jpg new file mode 100644 index 0000000..fb2051c Binary files /dev/null and b/assets/img/candidates/turner.jpg differ diff --git a/assets/img/candidates/winn.jpg b/assets/img/candidates/winn.jpg new file mode 100644 index 0000000..ff15d3a Binary files /dev/null and b/assets/img/candidates/winn.jpg differ diff --git a/assets/js/components/atoms/CandidateMatchPicture.jsx b/assets/js/components/atoms/CandidateMatchPicture.jsx index 69c5978..2b77a81 100644 --- a/assets/js/components/atoms/CandidateMatchPicture.jsx +++ b/assets/js/components/atoms/CandidateMatchPicture.jsx @@ -7,22 +7,92 @@ const style = { borderRadius: '100%', width: 72, height: 72, - background: colors.lightBlue + background: colors.lightBlue, + backgroundSize: 'contain' } } + + class CandidatePicture extends Component { + /* + * @name + * #getCandidatePicture + * @description + * Checks the contents of the users name. If a match is found, return the + * correct photo. This will be removed when the candidate image path comes + * from the backend. + */ + getImagePath(name) { + + let imgPath + + switch (name) { + case 'Kenneth Cooper Alexander': + imgPath = 'a/img/candidates/alexander.jpg' + break + + case 'Robert J. McCabe': + imgPath = '/img/candidates/mccabe.jpg' + break + + case 'Andy A. Protogyrou': + imgPath = '/img/candidates/protogyrou.jpg' + break + + case 'Andria P. McClellan': + imgPath = '/img/candidates/mcclellan.jpg' + break + + case 'Warren A. Stewart': + imgPath = '/img/candidates/stewart.jpg' + break + + case 'Barclay C. Winn': + imgPath = '/img/candidates/winn.jpg' + break + + case 'Harry David Candela': + imgPath = '/img/candidates/candela.jpg' + break + + case 'G.W. \'Billy\' Cook, Jr.': + imgPath = '/img/candidates/cook.jpg' + break + + case 'Angelia Williams Graves': + imgPath = '/img/candidates/graves.jpg' + break + + case 'Kendrick J. Turner': + imgPath = '/img/candidates/turner.jpg' + break + + default: + + } + + return { + background: `url(${imgPath})` + } + + } + + getStyle() { + return Object.assign({}, style.container, this.getImagePath(this.props.candidateName)) + } + render() { return ( -
- -
+
) } } -CandidatePicture.propTypes = {} +CandidatePicture.propTypes = { + candidateName: PropTypes.string +} export default CandidatePicture diff --git a/assets/js/components/atoms/CandidateMatchRating.jsx b/assets/js/components/atoms/CandidateMatchRating.jsx index 7fe27e6..0622aa5 100644 --- a/assets/js/components/atoms/CandidateMatchRating.jsx +++ b/assets/js/components/atoms/CandidateMatchRating.jsx @@ -32,8 +32,21 @@ class CandidateMatchRating extends Component { super(props) } + get colour() { + const thresholds = [ + { level: 80, colour: colors.yellow }, + { level: 60, colour: colors.orange }, + { level: 50, colour: colors.red} + ], match = parseInt(this.props.compositeMatchScore) + return thresholds.reduce((colour, threshold) => + match < threshold.level ? + threshold.colour : + colour, colors.green) + } + getContainerStyle() { - return Object.assign({}, style.container, this.props.style) + return Object.assign({}, style.container, this.props.style, + { background: this.colour }) } render() { diff --git a/assets/js/components/ecosystems/SurveyPage.jsx b/assets/js/components/ecosystems/SurveyPage.jsx index ca13fa4..5bb25b3 100644 --- a/assets/js/components/ecosystems/SurveyPage.jsx +++ b/assets/js/components/ecosystems/SurveyPage.jsx @@ -1,5 +1,6 @@ import React, {Component, PropTypes} from 'react' import { connect } from 'react-redux' +import { browserHistory } from 'react-router' import SurveyQuestionPager from './../ecosystems/SurveyQuestionPager.jsx' @@ -21,6 +22,13 @@ class SurveyPage extends Component { } componentWillMount() { + + // If survey response is undefined, redirect to front page so we can get it. + // Otherwise, the frontend won't be able to submit the survey. + if (!this.props.survey.surveyResponseId) { + browserHistory.push('/') + } + this.props.dispatch(fetchActiveSurveys()) } @@ -73,6 +81,7 @@ class SurveyPage extends Component { } SurveyPage.propTypes = { + location: PropTypes.object, survey: PropTypes.object, dispatch: PropTypes.func } diff --git a/assets/js/components/ecosystems/SurveyQuestionPager.jsx b/assets/js/components/ecosystems/SurveyQuestionPager.jsx index 7c950a2..a4d71ab 100644 --- a/assets/js/components/ecosystems/SurveyQuestionPager.jsx +++ b/assets/js/components/ecosystems/SurveyQuestionPager.jsx @@ -37,7 +37,7 @@ class SurveyQuestionPager extends Component { this.decrementIndex() } else { - browserHistory.push('/survey') + browserHistory.push('/') } } diff --git a/assets/js/components/molecules/CandidateMatchProfileBadge.jsx b/assets/js/components/molecules/CandidateMatchProfileBadge.jsx index d22091c..e6a9c88 100644 --- a/assets/js/components/molecules/CandidateMatchProfileBadge.jsx +++ b/assets/js/components/molecules/CandidateMatchProfileBadge.jsx @@ -27,8 +27,8 @@ class CandidateMatchProfileBadge extends Component { return (
- -
+ +

{this.props.candidateName}

-
+ style={style.panel}> { - this.state.showCategory ? this.props.categoryMatchScores.map((category, index) => { return ( ) }) - : - null } diff --git a/assets/js/components/organisms/CandidateMatchCategory.jsx b/assets/js/components/organisms/CandidateMatchCategory.jsx index f9ce9cc..884fe80 100644 --- a/assets/js/components/organisms/CandidateMatchCategory.jsx +++ b/assets/js/components/organisms/CandidateMatchCategory.jsx @@ -3,6 +3,14 @@ import { Panel } from 'react-bootstrap' import CandidateMatchRating from '../atoms/CandidateMatchRating.jsx' +const style = { + panel: { + marginBottom: '.5em', + marginLeft: -15, + marginRight: -15 + } +} + class CandidateMatchCategory extends Component { constructor(props) { super(props) @@ -10,7 +18,7 @@ class CandidateMatchCategory extends Component { render() { return ( - +

{this.props.categoryName} diff --git a/assets/js/components/style/colors.js b/assets/js/components/style/colors.js index 348d381..704d431 100644 --- a/assets/js/components/style/colors.js +++ b/assets/js/components/style/colors.js @@ -6,5 +6,10 @@ module.exports = { darkBlue: '#33425B', black: '#29252C', white: '#FDFDFD', - lightGray: '#efefef' + lightGray: '#efefef', + + // threshold colours + green: '#84ba71', + yellow: '#e0cc47', + orange: '#e89f31' } diff --git a/assets/style/main.css b/assets/style/main.css index 640b163..1bf83ca 100644 --- a/assets/style/main.css +++ b/assets/style/main.css @@ -11,7 +11,7 @@ body, html { padding: 3px 0; } -.candidate-card .collapse > .panel-body { +/*.candidate-card .collapse > .panel-body { padding-left: 0px; padding-right: 0px; -} +}*/ diff --git a/database/okcandidate_database_create.sql b/database/okcandidate_database_create.sql index 7bda4b3..f56aaf2 100644 --- a/database/okcandidate_database_create.sql +++ b/database/okcandidate_database_create.sql @@ -41,11 +41,6 @@ CREATE TABLE IF NOT EXISTS category ( category_name varchar(100) NOT NULL ); -CREATE TABLE IF NOT EXISTS data_type ( - id SERIAL PRIMARY KEY, - type_name varchar(100) NOT NULL -); - CREATE TABLE IF NOT EXISTS question ( id SERIAL PRIMARY KEY, survey_id int NOT NULL REFERENCES survey, @@ -82,8 +77,8 @@ CREATE TABLE IF NOT EXISTS candidate_type ( CREATE TABLE IF NOT EXISTS candidate ( id SERIAL PRIMARY KEY, candidate_name varchar(100), - candidate_img varchar(100), - candidate_website varchar(100), + candidate_img varchar(100), + candidate_website varchar(100), candidate_type_id int NOT NULL REFERENCES candidate_type ); diff --git a/database/okcandidate_database_sampledata.sql b/database/okcandidate_database_sampledata.sql index 463e3d1..d46e5fb 100644 --- a/database/okcandidate_database_sampledata.sql +++ b/database/okcandidate_database_sampledata.sql @@ -298,7 +298,259 @@ INSERT INTO candidate_answer (id, candidate_id, question_id, answer_id, intensit (105,7,33,89,5), (106,7,34,90,5), (107,7,35,93,5), -(108,7,36,96,5); +(108,7,36,96,5), +(109,10,1,1,5), +(110,10,2,4,5), +(111,10,3,9,5), +(112,10,4,11,5), +(113,10,5,14,5), +(114,10,6,16,5), +(115,10,7,19,5), +(116,10,8,20,5), +(117,10,9,22,5), +(118,10,10,26,5), +(119,10,11,28,5), +(120,10,12,31,5), +(121,10,13,33,5), +(122,10,14,35,5), +(123,10,15,38,5), +(124,10,16,41,5), +(125,10,17,43,5), +(126,10,18,46,5), +(127,10,19,49,5), +(128,10,20,53,5), +(129,10,21,56,5), +(130,10,22,58,5), +(131,10,23,60,5), +(132,10,24,62,5), +(133,10,25,66,5), +(134,10,26,67,5), +(135,10,27,70,5), +(136,10,28,73,5), +(137,10,29,78,5), +(138,10,30,79,5), +(139,10,31,82,5), +(140,10,32,84,5), +(141,10,33,87,5), +(142,10,34,90,5), +(143,10,35,94,5), +(144,10,36,96,5), +(145,4,1,1,5), +(146,4,2,4,5), +(147,4,3,9,5), +(148,4,4,12,5), +(149,4,5,14,5), +(150,4,6,17,5), +(151,4,7,19,5), +(152,4,8,20,5), +(153,4,9,23,1), +(154,4,10,24,5), +(155,4,11,28,5), +(156,4,12,31,5), +(157,4,13,34,5), +(158,4,14,35,5), +(159,4,15,40,5), +(160,4,16,41,5), +(161,4,17,43,5), +(162,4,18,46,5), +(163,4,19,50,5), +(164,4,20,52,5), +(165,4,21,57,5), +(166,4,22,58,5), +(167,4,23,60,5), +(168,4,24,62,3), +(169,4,25,66,5), +(170,4,26,69,2), +(171,4,27,71,4), +(172,4,28,73,4), +(173,4,29,78,5), +(174,4,30,80,5), +(175,4,31,83,5), +(176,4,32,85,5), +(177,4,33,88,5), +(178,4,34,92,3), +(179,4,35,94,4), +(180,4,36,96,5), +(181,2,1,1,5), +(182,2,2,4,5), +(183,2,3,9,5), +(184,2,4,12,5), +(185,2,5,14,5), +(186,2,6,16,5), +(187,2,7,19,5), +(188,2,8,20,5), +(189,2,9,22,5), +(190,2,10,26,5), +(191,2,11,28,5), +(192,2,12,32,5), +(193,2,13,34,5), +(194,2,14,35,5), +(195,2,15,40,5), +(196,2,16,41,5), +(197,2,17,44,3), +(198,2,18,45,5), +(199,2,19,50,5), +(200,2,20,52,5), +(201,2,21,57,5), +(202,2,22,58,5), +(203,2,23,60,5), +(204,2,24,62,3), +(205,2,25,66,5), +(206,2,26,69,5), +(207,2,27,70,5), +(208,2,28,73,5), +(209,2,29,78,5), +(210,2,30,79,5), +(211,2,31,83,5), +(212,2,32,85,5), +(213,2,33,88,5), +(214,2,34,91,4), +(215,2,35,94,5), +(216,2,36,96,5), +(217,5,1,2,3), +(218,5,2,5,3), +(219,5,3,9,3), +(220,5,4,13,3), +(221,5,5,14,4), +(222,5,6,17,4), +(223,5,7,18,5), +(224,5,8,20,2), +(225,5,9,23,1), +(226,5,10,27,4), +(227,5,11,28,3), +(228,5,12,31,5), +(229,5,13,34,5), +(230,5,14,35,5), +(231,5,15,40,5), +(232,5,16,42,2), +(233,5,17,43,5), +(234,5,18,46,3), +(235,5,19,50,4), +(236,5,20,53,3), +(237,5,21,57,4), +(238,5,22,58,5), +(239,5,23,60,4), +(240,5,24,63,2), +(241,5,25,64,3), +(242,5,26,68,3), +(243,5,27,71,2), +(244,5,28,73,3), +(245,5,29,78,4), +(246,5,30,81,2), +(247,5,31,83,4), +(248,5,32,84,5), +(249,5,33,87,5), +(250,5,34,92,1), +(251,5,35,94,3), +(252,5,36,97,5), +(253,1,1,1,5), +(254,1,2,4,5), +(255,1,3,7,5), +(256,1,4,12,5), +(257,1,5,14,4), +(258,1,6,16,5), +(259,1,7,19,5), +(260,1,8,20,5), +(261,1,9,23,1), +(262,1,10,26,5), +(263,1,11,28,5), +(264,1,12,32,5), +(265,1,13,34,5), +(266,1,14,35,5), +(267,1,15,40,5), +(268,1,16,42,1), +(269,1,17,44,5), +(270,1,18,48,5), +(271,1,19,50,5), +(272,1,20,53,5), +(273,1,21,57,5), +(274,1,22,59,5), +(275,1,23,61,5), +(276,1,24,62,1), +(277,1,25,65,5), +(278,1,26,68,3), +(279,1,27,70,3), +(280,1,28,74,4), +(281,1,29,76,5), +(282,1,30,81,3), +(283,1,31,83,5), +(284,1,32,85,5), +(285,1,33,89,5), +(286,1,34,92,1), +(287,1,35,94,5), +(288,1,36,97,5), +(289,3,1,1,5), +(290,3,2,4,5), +(291,3,3,9,5), +(292,3,4,12,5), +(293,3,5,14,5), +(294,3,6,16,5), +(295,3,7,18,5), +(296,3,8,20,5), +(297,3,9,22,4), +(298,3,10,24,5), +(299,3,11,28,4), +(300,3,12,31,5), +(301,3,13,33,5), +(302,3,14,35,5), +(303,3,15,39,5), +(304,3,16,41,5), +(305,3,17,44,5), +(306,3,18,46,5), +(307,3,19,49,5), +(308,3,20,53,5), +(309,3,21,55,5), +(310,3,22,58,5), +(311,3,23,60,5), +(312,3,24,62,4), +(313,3,25,66,5), +(314,3,26,68,5), +(315,3,27,70,5), +(316,3,28,74,5), +(317,3,29,78,5), +(318,3,30,80,4), +(319,3,31,82,5), +(320,3,32,84,5), +(321,3,33,89,5), +(322,3,34,91,5), +(323,3,35,94,5), +(324,3,36,96,5), +(325,9,1,1,4), +(326,9,2,5,4), +(327,9,3,9,3), +(328,9,4,11,3), +(329,9,5,15,1), +(330,9,6,17,1), +(331,9,7,19,5), +(332,9,8,20,3), +(333,9,9,23,1), +(334,9,10,25,4), +(335,9,11,29,2), +(336,9,12,30,4), +(337,9,13,33,5), +(338,9,14,35,4), +(339,9,15,38,5), +(340,9,16,42,3), +(341,9,17,44,5), +(342,9,18,47,3), +(343,9,19,51,4), +(344,9,20,53,4), +(345,9,21,57,3), +(346,9,22,58,5), +(347,9,23,60,5), +(348,9,24,62,1), +(349,9,25,64,4), +(350,9,26,68,3), +(351,9,27,70,4), +(352,9,28,74,3), +(353,9,29,78,4), +(354,9,30,79,4), +(355,9,31,82,5), +(356,9,32,85,5), +(357,9,33,89,5), +(358,9,34,91,1), +(359,9,35,95,5), +(360,9,36,97,5); ------------------------- -- Candidate Geography -- diff --git a/design/loading survey.png b/design/loading survey.png new file mode 100644 index 0000000..2f3fe82 Binary files /dev/null and b/design/loading survey.png differ diff --git a/design/okcandidate-wireframes.bmpr b/design/okcandidate-wireframes.bmpr index d81e9d5..e8a09a0 100644 Binary files a/design/okcandidate-wireframes.bmpr and b/design/okcandidate-wireframes.bmpr differ diff --git a/test/frontend/components/atoms/CandidateMatchRatingSpec.js b/test/frontend/components/atoms/CandidateMatchRatingSpec.js new file mode 100644 index 0000000..d8c500c --- /dev/null +++ b/test/frontend/components/atoms/CandidateMatchRatingSpec.js @@ -0,0 +1,111 @@ +import React from 'react' +import TestUtils from 'react-addons-test-utils' +import { expect } from 'chai' + +import CandidateMatchRating + from '../../../../assets/js/components/atoms/CandidateMatchRating' +import colours + from '../../../../assets/js/components/style/colors' + +describe('The candidate match rating component', () => { + let rating + + beforeEach(() => { + rating = TestUtils.renderIntoDocument( + + ) + }) + + it('will exist', () => { + expect(rating).to.be.ok + }) + + context('colour', () => { + let colour + + beforeEach(() => { + colour = rating.colour + }) + + it('will exist', () => { + expect(colour).to.be.ok + }) + + it('will start with the red colour in the common style colours', () => { + expect(colour).to.equal(colours.red) + }) + }) + + context('container style', () => { + let style + + beforeEach(() => { + style = rating.getContainerStyle() + }) + + it('will exist', () => { + expect(style).to.be.ok + }) + + it('will have the common red style colour in its background', () => { + expect(style).to.have.property('background') + .that.equal(colours.red) + }) + + context('with a less than 50% match', () => { + beforeEach(() => { + rating = TestUtils.renderIntoDocument( + + ) + style = rating.getContainerStyle() + }) + + it('will have a red background', () => { + expect(style).to.have.property('background') + .that.equal(colours.red) + }) + }) + + context('with a match between 50% and 60%', () => { + beforeEach(() => { + rating = TestUtils.renderIntoDocument( + + ) + style = rating.getContainerStyle() + }) + + it('will have an orange background', () => { + expect(style).to.have.property('background') + .that.equal(colours.orange) + }) + }) + + context('with a match between 60% and 80%', () => { + beforeEach(() => { + rating = TestUtils.renderIntoDocument( + + ) + style = rating.getContainerStyle() + }) + + it('will have a yellow background', () => { + expect(style).to.have.property('background') + .that.equal(colours.yellow) + }) + }) + + context('with a match above 80%', () => { + beforeEach(() => { + rating = TestUtils.renderIntoDocument( + + ) + style = rating.getContainerStyle() + }) + + it('will have a green background', () => { + expect(style).to.have.property('background') + .that.equal(colours.green) + }) + }) + }) +}) diff --git a/views/Default.jsx b/views/Default.jsx index 27efe23..6c8d8bd 100644 --- a/views/Default.jsx +++ b/views/Default.jsx @@ -4,6 +4,16 @@ const React = require('react'); const Default = React.createClass({ + componentDidMount() { + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','https://www.google-analytics.com/analytics.js','ga') + + ga('create', 'UA-39303796-10', 'auto'); + ga('send', 'pageview'); + }, + render: function() { return(