Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
f265c16
setup generic
prd-duy-huynh Jun 11, 2025
48dc4be
add generic component graphql
prd-duy-huynh Jun 11, 2025
ddad0df
render questions
prd-duy-huynh Jun 13, 2025
07d1ad5
render questions and collect answers
prd-duy-huynh Jun 15, 2025
d065fc4
refactor
prd-duy-huynh Jun 15, 2025
662aecb
handle multi questions set
prd-duy-huynh Jun 16, 2025
b0cf037
add conclusions view
prd-duy-huynh Jun 17, 2025
aeeb84b
add show instructions
prd-duy-huynh Jun 17, 2025
612d3fe
update Modal common
prd-duy-huynh Jun 17, 2025
0ca367b
submit answers
prd-duy-huynh Jun 20, 2025
26c932f
Merge branch 'master' into TD-2435-generic-assessment-ui
prd-duy-huynh Jun 20, 2025
aa365bb
use assessmentID
prd-duy-huynh Jun 20, 2025
2874102
bump version
prd-duy-huynh Jun 20, 2025
8a997c1
refactor
prd-duy-huynh Jun 20, 2025
a17c8c4
update graphql responses
prd-duy-huynh Jun 24, 2025
8e04610
refactor code
prd-duy-huynh Jun 27, 2025
0664436
add retry attempts
prd-duy-huynh Jun 27, 2025
4295879
render score
prd-duy-huynh Jun 28, 2025
317f1d0
remove secret key
prd-duy-huynh Jul 17, 2025
57db093
Merge branch 'master' into TD-2435-generic-assessment-ui
prd-duy-huynh Jul 17, 2025
869c028
render breakdown
prd-duy-huynh Jul 21, 2025
398f21f
apply space-between
prd-duy-huynh Jul 23, 2025
b262188
show hide all
prd-duy-huynh Jul 23, 2025
7ce3439
format
prd-duy-huynh Jul 23, 2025
cfb3a3c
handle question with set image
prd-duy-huynh Jul 24, 2025
33408ce
Merge branch 'TD-2435-generic-assessment-ui' into TD-2500-render-results
prd-duy-huynh Jul 24, 2025
02fde09
handle locale
prd-duy-huynh Jul 25, 2025
a2537ab
update heading and hr tag
prd-duy-huynh Jul 30, 2025
cd2a674
helper
prd-duy-huynh Jul 30, 2025
91a5ed8
rearrange css class
prd-duy-huynh Jul 30, 2025
c4bd1f8
use translate
prd-duy-huynh Aug 1, 2025
a50b734
parse completedAt by millisecond
prd-duy-huynh Aug 4, 2025
4152072
Merge branch 'master' into TD-2500-render-results
prd-duy-huynh Aug 12, 2025
43315d5
Added loading state
tomprats Aug 12, 2025
80c930f
remove header and actions
prd-duy-huynh Aug 13, 2025
e416ea3
Merge branch 'master' into TD-2500-render-results
prd-duy-huynh Aug 16, 2025
3241452
set loaded active assessment + remove redundant generic result css
prd-duy-huynh Aug 18, 2025
bfafcb5
bump version to 3.9.0
prd-duy-huynh Aug 18, 2025
1770629
extend box and container
prd-duy-huynh Aug 18, 2025
1d57f34
extend container
prd-duy-huynh Aug 18, 2025
2825d0f
refactor btn border
prd-duy-huynh Aug 18, 2025
4529d36
return after setActive
prd-duy-huynh Aug 20, 2025
71e7faf
name format
prd-duy-huynh Aug 21, 2025
a51a651
get result if completed
prd-duy-huynh Aug 21, 2025
2c2def5
not return cached survey if completed
prd-duy-huynh Aug 29, 2025
1ba75f1
not call to result api
prd-duy-huynh Sep 5, 2025
5d42077
render totalCorrectResponses
prd-duy-huynh Sep 8, 2025
4a48daf
let question set in column for mobile
prd-duy-huynh Sep 18, 2025
5ac1e92
survey mobile
prd-duy-huynh Sep 19, 2025
9df964e
refactor direction class
prd-duy-huynh Sep 19, 2025
e17e6a3
update btn mobile
prd-duy-huynh Sep 19, 2025
173ecda
update reserved words
prd-duy-huynh Sep 19, 2025
e8f085c
refactor with early return
prd-duy-huynh Sep 19, 2025
d52a623
refactor progress bar
prd-duy-huynh Sep 19, 2025
034eb57
add Generic components
prd-duy-huynh Sep 19, 2025
9b84208
render score from api
prd-duy-huynh Sep 20, 2025
23896f8
Merge branch 'master' into TD-2500-render-results
prd-duy-huynh Sep 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "traitify-widgets",
"version": "3.8.2",
"version": "3.9.0",
"description": "Traitiy Widgets",
"repository": {
"type": "git",
Expand Down
49 changes: 48 additions & 1 deletion public/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ function createAssessment() {
if(cache.get("surveyType") === "benchmark") { return createWidget(); }
if(cache.get("surveyType") === "cognitive") { return createCognitiveAssessment(); }
if(cache.get("surveyType") === "order") { return createWidget(); }
if(cache.get("surveyType") === "generic") { return createGenericAssessment(); }

const params = {
deck_id: cache.get("deckID"),
Expand Down Expand Up @@ -240,6 +241,24 @@ function createElement(options = {}) {
return element;
}

function createGenericAssessment() {
const query = Traitify.GraphQL.generic.create;
const variables = {
surveyID: cache.get("surveyID"),
profileID: cache.get("profileID")
};

Traitify.http.post(Traitify.GraphQL.generic.path, {query, variables}).then((response) => {
try {
const id = response.data.getOrCreateGenericAssessment.id;
cache.set("assessmentID", id);
} catch(error) {
console.log(error);
}
setTimeout(createWidget, 500);
});
}

function destroyWidget() { Traitify.destroy(); }

function setupTargets() {
Expand Down Expand Up @@ -369,6 +388,7 @@ function setupDom() {
options: [
{text: "Benchmark", value: "benchmark"},
{text: "Cognitive", value: "cognitive"},
{text: "Generic", value: "generic"},
{text: "Order", value: "order"},
{text: "Personality", value: "personality"}
],
Expand Down Expand Up @@ -404,6 +424,9 @@ function setupDom() {
row.appendChild(createOption({name: "orderID", text: "Order ID:"}));
group.appendChild(row)

row = createElement({className: surveyType !== "generic" ? "hide" : "", id: "generic-options"});
row.appendChild(createOption({name: "profileID", text: "Profile ID:"}));
group.appendChild(row);
row = createElement({className: "row"});
row.appendChild(createElement({onClick: createAssessment, tag: "button", text: "Create / Load"}));
group.appendChild(row);
Expand All @@ -427,6 +450,29 @@ function setupCognitive() {
});
}

function setupGeneric() {
const query = Traitify.GraphQL.generic.surveys;
const variables = {localeKey: cache.get("locale")};

Traitify.http.post(Traitify.GraphQL.generic.path, {query, variables}).then((response) => {
try {
const options = response.data.genericSurveys
.map(({id, name}) => ({text: name, value: id}))
.sort((a, b) => a.text.localeCompare(b.text));

document.querySelector("#generic-options").appendChild(createOption({
name: "surveyID",
onChange: onInputChange,
options,
text: "Survey:"
}));
} catch(error) {
console.log(error);
}
});

}

function setupTraitify() {
const environment = cache.get("environment");

Expand Down Expand Up @@ -455,7 +501,7 @@ function onSurveyTypeChange(e) {
const name = e.target.name;
const value = e.target.value;
const assessmentID = cache.get(`${value}AssessmentID`);
const otherValues = ["benchmark", "cognitive", "order", "personality"].filter((type) => type !== value);
const otherValues = ["benchmark", "cognitive", "generic", "order", "personality"].filter((type) => type !== value);

cache.set("assessmentID", assessmentID);

Expand All @@ -468,4 +514,5 @@ function onSurveyTypeChange(e) {
setupTraitify();
setupDom();
setupCognitive();
setupGeneric();
createWidget();
6 changes: 4 additions & 2 deletions src/components/common/modal/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import Icon from "components/common/icon";
import useTranslate from "lib/hooks/use-translate";
import style from "./style.scss";

export default function Modal({children, onClose, title}) {
export default function Modal({children, containerClass = null, onClose, title}) {
const translate = useTranslate();
const sectionClass = [style.modalContainer, containerClass].filter(Boolean).join(" ");
return (
<div className={`${style.modal} ${style.container}`}>
<section className={style.modalContainer}>
<section className={sectionClass}>
<div className={style.modalContent}>
<div className={style.header}>
<div>{title}</div>
Expand All @@ -34,6 +35,7 @@ export default function Modal({children, onClose, title}) {

Modal.propTypes = {
children: PropTypes.node.isRequired,
containerClass: PropTypes.string,
onClose: PropTypes.func.isRequired,
title: PropTypes.string.isRequired
};
6 changes: 4 additions & 2 deletions src/components/container/hooks/use-order-effect.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ export default function useOrderEffect() {
// NOTE: Start next assessment
if(currentAssessment.completed) {
const nextAssessment = order.assessments.find(({completed}) => !completed);
if(nextAssessment) { setActive({...nextAssessment}); }
if(nextAssessment) {
setActive({...nextAssessment});

return;
return;
}
}

// NOTE: Load updates for active assessment
Expand Down
4 changes: 4 additions & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import CareerList from "./results/career/list";
import CareerModal from "./results/career/modal";
import CognitiveResults from "./results/cognitive";
import CognitiveChart from "./results/cognitive/chart";
import GenericResults from "./results/generic";
import ClientGuide from "./results/guide/client";
import PersonalityGuide from "./results/guide/personality";
import ArchetypeHeading from "./results/personality/archetype/heading";
Expand All @@ -30,6 +31,7 @@ import RecommendationChart from "./results/recommendation/chart";
import Status from "./status";
import Survey from "./survey";
import CognitiveSurvey from "./survey/cognitive";
import GenericSurvey from "./survey/generic";
import PersonalitySurvey from "./survey/personality";

export default {
Expand All @@ -54,6 +56,7 @@ export default {
Container: CognitiveResults
},
Container: Results,
Generic: GenericResults,
Guide: {
Client: ClientGuide,
Personality: PersonalityGuide
Expand Down Expand Up @@ -90,6 +93,7 @@ export default {
Survey: {
Cognitive: CognitiveSurvey,
Container: Survey,
Generic: GenericSurvey,
Personality: PersonalitySurvey
}
};
59 changes: 59 additions & 0 deletions src/components/results/generic/breakdown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import PropTypes from "prop-types";
import {useState} from "react";
import useTranslate from "lib/hooks/use-translate";
import Question from "./question";
import style from "./style.scss";

export default function Breakdown({assessmentResult}) {
const [showAll, setShowAll] = useState(false);
const translate = useTranslate();
const showHideAll = () => {
setShowAll(!showAll);
};

return (
<div className={style.breakdown}>
<div className={style.description}>
<div>
<div className={style.title}>{translate("results.generic.breakdown")}</div>
<span>{translate("results.generic.breakdown_description")}</span>
</div>
<div>
<button className={style.toggleButton} type="button" onClick={showHideAll}>
{translate("show_hide_all")}
</button>
</div>
</div>
<div className={style.questions}>
{assessmentResult.responses.map((question, index) => (
<Question
key={question.questionId}
question={question}
index={index}
showState={showAll}
/>
))}
</div>
</div>
);
}

Breakdown.propTypes = {
assessmentResult: PropTypes.shape({
responses: PropTypes.arrayOf(
PropTypes.shape({
questionId: PropTypes.string.isRequired,
questionText: PropTypes.string,
isCorrect: PropTypes.bool.isRequired,
selectedResponseOptionId: PropTypes.string,
responseOptions: PropTypes.arrayOf(
PropTypes.shape({
responseOptionId: PropTypes.string.isRequired,
responseOptionText: PropTypes.string.isRequired,
isCorrect: PropTypes.bool
})
).isRequired
})
).isRequired
}).isRequired
};
20 changes: 20 additions & 0 deletions src/components/results/generic/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import useResults from "lib/hooks/use-results";
import Breakdown from "./breakdown";
import Score from "./score";
import style from "./style.scss";

export default function GenericResults() {
const result = useResults({surveyType: "generic"});
if(!result) { return null; }

return (
<div>
<div className={style.container}>
<div className={style.contentBody}>
<Score assessmentResult={result} />
<Breakdown assessmentResult={result} />
</div>
</div>
</div>
);
}
95 changes: 95 additions & 0 deletions src/components/results/generic/question.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import {faCheck, faXmark, faChevronDown, faChevronUp} from "@fortawesome/free-solid-svg-icons";
import PropTypes from "prop-types";
import {useState, useEffect} from "react";
import Icon from "components/common/icon";
import useTranslate from "lib/hooks/use-translate";
import style from "./style.scss";

export default function Question({question, index, showState}) {
const translate = useTranslate();
const [showContent, setShowContent] = useState(false);
const longTextCondition = (option) => option.responseOptionText.length > 20;
const longTextResponses = question.responseOptions.some(longTextCondition);
const directionClass = (longTextResponses || question.setImage) ? style.flexDirectionColumn : "";
const responsesClassName = (question.setImage)
? [style.responsesWithImage, directionClass].join(" ")
: [style.responsesWithoutImage, directionClass].join(" ");

useEffect(() => {
setShowContent(showState);
}, [showState]);

const toggleContent = () => {
setShowContent(!showContent);
};

const optionClassName = (option) => {
if(question.isCorrect) {
return option.isCorrect ? style.correctResponse : "";
}
if(option.isCorrect) {
return style.correctOption;
}
if(option.responseOptionId === question.selectedResponseOptionId) {
return style.incorrectResponse;
}
return "";
};

return (
<div key={question.questionId} className={style.question}>
<div className={style.questionTitle}>
<div>
{question.isCorrect
? <Icon className={style.iconCorrect} alt="Checked" icon={faCheck} />
: <Icon className={style.iconIncorrect} alt="X Mark" icon={faXmark} />}
</div>
<div> {translate("cognitive_question_alt_text")} {index + 1}</div>
<div>
<button type="button" onClick={toggleContent} className={style.toggleButton}>
<Icon className={style.icon} alt="Expand" icon={showContent ? faChevronUp : faChevronDown} />
</button>
</div>
</div>
{showContent && (
<div className={style.questionContent}>
<div className={style.responseOptions}>
<div className={style.questionText}>{question.questionText}</div>
<div className={responsesClassName}>
{question.responseOptions.map((option) => (
<div
key={option.responseOptionId}
className={`${optionClassName(option)} ${style.responseOption}`}
>
{option.responseOptionText}
</div>
))}
</div>
</div>
{question.setImage && (
<div className={style.questionImage}>
<img src={question.setImage} alt={question.questionText} />
</div>
)}
</div>
)}
</div>
);
}

Question.propTypes = {
question: PropTypes.shape({
questionText: PropTypes.string,
questionId: PropTypes.string.isRequired,
isCorrect: PropTypes.bool.isRequired,
selectedResponseOptionId: PropTypes.string,
setImage: PropTypes.string,
responseOptions: PropTypes.arrayOf(PropTypes.shape({
responseOptionId: PropTypes.string.isRequired,
responseOptionText: PropTypes.string.isRequired,
isCorrect: PropTypes.bool.isRequired
})).isRequired
}).isRequired,
index: PropTypes.number.isRequired,
showState: PropTypes.bool.isRequired
};
Loading