Skip to content

Commit

Permalink
[WIP] Trying things
Browse files Browse the repository at this point in the history
  • Loading branch information
Gavriil-Tzortzakis committed Nov 2, 2024
1 parent 671a26e commit c6ea5d5
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 0 deletions.
22 changes: 22 additions & 0 deletions shared/locales/en/website-responses.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"title": "Survey Responses",
"onboarding": {
"title": "Onboarding Survey",
"description": "Filled out once before recipient is joining the program"
},
"checkin": {
"title": "Check-in Survey",
"description": "Filled out every 6 months while recipient is in the program"
},
"offboarding": {
"title": "Offboarding Survey",
"description": "Filled out once when recipient is finishing the program"
},
"offboarded-checkin": {
"title": "Follow-up Survey",
"description": "Filled out every 6 months after recipient left the program"
}



}
72 changes: 72 additions & 0 deletions shared/src/utils/stats/SurveyStatsCalculator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import _ from 'lodash';
import { FirestoreAdmin } from '../../firebase/admin/FirestoreAdmin';
import { Recipient, RECIPIENT_FIRESTORE_PATH } from '../../types/recipient';
import { Survey, SURVEY_FIRETORE_PATH, SurveyQuestionnaire, SurveyStatus } from '../../types/survey';

export interface SurveyStats {
total: number;
type: SurveyQuestionnaire;
}

export interface SurveyAnswersByType {
answers: any[];
}

export class SurveyStatsCalculator {
private readonly _data: SurveyStats[];
private readonly _aggregatedData: { [key: string]: { [key: string]: SurveyAnswersByType } };

private constructor(
data: SurveyStats[],
aggregatedData: {
[key: string]: { [key: string]: SurveyAnswersByType };
},
) {
this._data = data;
this._aggregatedData = aggregatedData;
}

/**
* @param firestoreAdmin
*/
static async build(firestoreAdmin: FirestoreAdmin): Promise<SurveyStatsCalculator> {
const recipients = await firestoreAdmin.collection<Recipient>(RECIPIENT_FIRESTORE_PATH).get();
let documents = await Promise.all(
recipients.docs
.filter((recipient) => !recipient.get('test_recipient'))
.map(async (recipient) => {
return await firestoreAdmin
.collection<Survey>(`${RECIPIENT_FIRESTORE_PATH}/${recipient.id}/${SURVEY_FIRETORE_PATH}`)
.get();
}),
);
let ignored = ['pageNo'];
let surveysData = documents.flatMap((snapshot) => snapshot.docs).map((survey) => survey.data());

let aggregatedData: { [key: string]: { [key: string]: SurveyAnswersByType } } = {};
const typeCounts: { [type: string]: number } = {};
surveysData.forEach((item) => {
if (item.status === SurveyStatus.Completed) {
typeCounts[item.questionnaire] = (typeCounts[item.questionnaire] || 0) + 1;
for (const [key, value] of Object.entries(item.data)) {
if (!ignored.includes(key)) {
aggregatedData[item.questionnaire] = aggregatedData[item.questionnaire] || {};
aggregatedData[item.questionnaire][key] = aggregatedData[item.questionnaire][key] || { answers: [] };
aggregatedData[item.questionnaire][key].answers.push(value);
}
}
}
});
const data = Object.entries(typeCounts).map(([type, total]) => ({ type, total }) as SurveyStats);

return new SurveyStatsCalculator(data, aggregatedData);
}

get data(): SurveyStats[] {
return this._data;
}

get aggregatedData(): { [key: string]: { [key: string]: SurveyAnswersByType } } {
return this._aggregatedData;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { firestoreAdmin } from '@/firebase-admin';
import { SurveyStatsCalculator } from '@socialincome/shared/src/utils/stats/SurveyStatsCalculator';
import { Badge, BaseContainer, Card, CardTitle, Typography } from '@socialincome/ui';
import { Translator } from '@socialincome/shared/src/utils/i18n';
import { DefaultPageProps } from '@/app/[lang]/[region]';
import { SurveyQuestionnaire } from '@socialincome/shared/src/types/survey';

export const revalidate = 3600; // update once an hour
export default async function Page({ params: { lang } }: DefaultPageProps) {
const surveyStatsCalculator = await SurveyStatsCalculator.build(firestoreAdmin);
const temp = surveyStatsCalculator.data;
const allSurveyData = Object.values(SurveyQuestionnaire).map((it) => temp.find((survey) => survey.type == it));
const data = surveyStatsCalculator.aggregatedData;
const translator = await Translator.getInstance({
language: lang,
namespaces: ['website-responses','website-survey'],
});
let selectedSurvey = SurveyQuestionnaire.Onboarding;

return (
<BaseContainer className="mx-auto flex max-w-3xl flex-col space-y-12">
<Typography size="4xl" weight="bold">
{translator.t('title')}
</Typography>
<div className="flex flex-col space-y-2 py-4">
<div className="mt-2 grid grid-cols-4 gap-2">
{allSurveyData.map(
(surveyData) =>
surveyData && (
<Card key={surveyData.type} className="p-2 bg-neutral-50">
<CardTitle className="text py-2">{translator.t(surveyData.type + '.title')}</CardTitle>

<Typography className="mt-2">{translator.t(surveyData.type + '.description')}</Typography>
<Typography className="mt-3">{surveyData.total} data points</Typography>
</Card>
),
)}
</div>
</div>
<div className="flex flex-col">
<div className="mt-2 grid grid-cols-1 gap-2">
{Object.keys(data[selectedSurvey]).map((key) => (
<Card key={key} className="p-2 bg-transparent">
<CardTitle>
<div>
<Typography className="text py-2">{translator.t('survey.questions.'+key.replace("V1","TitleV1"))}</Typography>
<Badge className="bg-amber-400">
<Typography className="mt-1 ">{data[selectedSurvey][key].answers.length} answers</Typography>
</Badge>
</div>
</CardTitle>
<div>
<Typography className="mt-2">{JSON.stringify(data[selectedSurvey][key].answers)}</Typography>
</div>
</Card>


))}
</div>
</div>
</BaseContainer>
);
}

0 comments on commit c6ea5d5

Please sign in to comment.