92 lines
3.3 KiB
TypeScript
92 lines
3.3 KiB
TypeScript
import { QuestionType } from "@/types";
|
|
|
|
/**
|
|
* Narcissistic Personality Inventory calculator parameters interface
|
|
*/
|
|
interface NPDCalculatorProps {
|
|
/** Answer data, key is question ID, value is selected score */
|
|
answers: { [key: number]: string };
|
|
/** Questions list */
|
|
questions: QuestionType[];
|
|
}
|
|
|
|
/**
|
|
* Calculate Narcissistic Personality Inventory (NPI-16) results
|
|
*
|
|
* @param answers - User answer data, containing question ID and selected score
|
|
* @returns Calculation results, including total score, factor scores, severity level and other information
|
|
*/
|
|
export const calculateNPDResults = ({ answers }: NPDCalculatorProps): any => {
|
|
// NPI-16 calculation logic
|
|
let totalScore = 0;
|
|
|
|
// Subscale score initialization based on NPI factors
|
|
let leadershipAuthorityScore = 0; // Leadership/Authority subscale
|
|
let grandioseExhibitionismScore = 0; // Grandiose Exhibitionism subscale
|
|
let entitlementScore = 0; // Entitlement subscale
|
|
|
|
// Calculate total score and subscale scores
|
|
Object.entries(answers).forEach(([questionId, score]) => {
|
|
const questionNum = parseInt(questionId);
|
|
const scoreValue = parseInt(score);
|
|
|
|
totalScore += scoreValue;
|
|
|
|
// Assign to subscales based on NPI-16 factor structure
|
|
// Leadership/Authority: questions 1, 8, 10, 11, 12
|
|
if ([1, 8, 10, 11, 12].includes(questionNum)) {
|
|
leadershipAuthorityScore += scoreValue;
|
|
}
|
|
// Grandiose Exhibitionism: questions 2, 3, 7, 15
|
|
else if ([2, 3, 7, 15].includes(questionNum)) {
|
|
grandioseExhibitionismScore += scoreValue;
|
|
}
|
|
// Entitlement: questions 4, 5, 6, 9, 13, 14, 16
|
|
else if ([4, 5, 6, 9, 13, 14, 16].includes(questionNum)) {
|
|
entitlementScore += scoreValue;
|
|
}
|
|
});
|
|
|
|
// Determine interpretation level based on total score
|
|
// Based on research, average scores typically range from 2-8 in general population
|
|
let interpretation = "low";
|
|
if (totalScore >= 4 && totalScore <= 7) {
|
|
interpretation = "average";
|
|
} else if (totalScore >= 8 && totalScore <= 11) {
|
|
interpretation = "above_average";
|
|
} else if (totalScore >= 12) {
|
|
interpretation = "high";
|
|
}
|
|
|
|
// Calculate percentile approximation
|
|
let percentile = 0;
|
|
if (totalScore <= 2) percentile = 25;
|
|
else if (totalScore <= 5) percentile = 50;
|
|
else if (totalScore <= 8) percentile = 75;
|
|
else if (totalScore <= 11) percentile = 90;
|
|
else percentile = 95;
|
|
|
|
// Calculate factor scores
|
|
const factorScores: { [key: string]: number } = {
|
|
"leadership": leadershipAuthorityScore,
|
|
"exhibitionism": grandioseExhibitionismScore,
|
|
"entitlement": entitlementScore
|
|
};
|
|
|
|
// Identify dominant traits
|
|
const dominantTrait = Object.entries(factorScores).reduce((a, b) =>
|
|
factorScores[a[0]] > factorScores[b[0]] ? a : b
|
|
)[0];
|
|
|
|
// Return complete calculation results
|
|
return {
|
|
totalScore,
|
|
factorScores,
|
|
positiveItemCount: totalScore, // For NPI, each item is either 0 or 1
|
|
positiveItemAverage: totalScore / Object.keys(answers).length,
|
|
isSevere: interpretation === "high",
|
|
interpretation,
|
|
percentile,
|
|
dominantTrait,
|
|
};
|
|
}; |