Skip to content

Commit

Permalink
adjust finding of suitable applications
Browse files Browse the repository at this point in the history
  • Loading branch information
Max-vS committed Jun 2, 2024
1 parent a438e20 commit e32aa36
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 15 deletions.
25 changes: 17 additions & 8 deletions app/opportunities/[opportunity_id]/review/new/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,38 @@ export default async function StartReview({ params }: StartReviewProps) {
},
});

console.log(applications);

let suitableApplication = null;
let suitableQuestionnaire = null;

// Iterate over applications to find the first suitable one
for (const application of applications) {
// Find a suitable questionnaire within this application
suitableQuestionnaire = application.questionnaires.find(
(questionnaire) =>
questionnaire.reviewers.some(
(reviewer) => reviewer.id === session.user.id,
) && // User is a reviewer
suitableQuestionnaire = application.questionnaires.find((questionnaire) => {
// User is a reviewer
const isReviewer = questionnaire.reviewers.some(
(reviewer) => reviewer.id === session.user.id,
);

// User has not reviewed questionnaire and application together
const hasNotReviewed =
questionnaire.reviews.filter(
(review) =>
review.userId === session.user.id &&
review.questionnaireId === questionnaire.id &&
review.applicationId === application.id,
).length === 0 && // User has not reviewed questionnaire and application together
).length === 0;

const lessReviewsThanRequired =
questionnaire.reviews.filter(
(review) =>
review.questionnaireId === questionnaire.id &&
review.applicationId === application.id,
).length < questionnaire.requiredReviews, // Less reviews than required
);
).length < questionnaire.requiredReviews;

return isReviewer && hasNotReviewed && lessReviewsThanRequired;
});

if (suitableQuestionnaire) {
suitableApplication = application;
Expand Down
159 changes: 159 additions & 0 deletions lib/faker/applications.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { faker } from "@faker-js/faker";
import { Tally, TallyData, TallyField } from "@lib/types/tally";
import { keyUniqueEnforcer, now, options } from "./utils";
import db from "server/db";

enum FieldTypes {
CHECKBOXES = "CHECKBOXES",
MULTIPLE_CHOICE = "MULTIPLE_CHOICE",
DROPDOWN = "DROPDOWN",
}

enum NormalFieldTypes {
TEXTAREA = "TEXTAREA",
INPUT_TEXT = "INPUT_TEXT",
INPUT_NUMBER = "INPUT_NUMBER",
INPUT_DATE = "INPUT_DATE",
INPUT_EMAIL = "INPUT_EMAIL",
INPUT_LINK = "INPUT_LINK",
}

type Application = {
content: Tally;
opportunity: number;
};

const minNumberOfApplications = parseInt(options.minapplications, 10);
const maxNumberOfApplications = parseInt(options.maxapplications, 10);

export async function generateApplications(opportunityIds: number[]) {
const applications: Application[] = opportunityIds.flatMap((id) =>
Array.from(
{
length: faker.number.int({
min: minNumberOfApplications,
max: maxNumberOfApplications,
}),
},
() => generateApplication(id),
),
);

for (const application of applications) {
await db.application.create({
data: {
content: application.content,
opportunity: { connect: { id: application.opportunity } },
},
});
}

return applications;
}

function generateApplication(opportunityId: number): Application {
return {
content: generateTallyContent(),
opportunity: opportunityId,
};
}

function generateTallyContent(): Tally {
return {
eventId: faker.string.uuid(),
eventType: "FORM_RESPONSE",
createdAt: now.toISOString(),
data: generateTallyData(),
};
}

function generateTallyData(): TallyData {
return {
responseId: faker.string.nanoid(6),
submissionId: faker.string.nanoid(6),
respondentId: faker.string.nanoid(6),
formId: faker.string.nanoid(6),
formName: faker.science.chemicalElement().name,
createdAt: now.toISOString(),
fields: Array.from({ length: 2 }, () => generateTallyField()),
};
}

function generateTallyField(): TallyField {
const fieldTypes: (string | FieldTypes)[] = Object.values(FieldTypes);
const fieldType = faker.helpers.arrayElement(fieldTypes);

const baseField = {
label: faker.music.genre(),
key: keyUniqueEnforcer.enforce(() => faker.string.nanoid(6)),
};

return generateTallyFieldDetails(baseField, fieldType);
}

function generateTallyFieldDetails(
baseField: {
label: string;
key: string;
},
fieldType: string | FieldTypes,
): TallyField {
switch (fieldType) {
case FieldTypes.CHECKBOXES:
const checkbox_options = Array.from(
{ length: faker.number.int({ min: 1, max: 4 }) },
() => ({ id: faker.string.uuid(), text: faker.music.songName() }),
);
return {
...baseField,
type: FieldTypes.CHECKBOXES,
value: faker.helpers.arrayElements(
checkbox_options.map((o) => o.id),
{ min: 1, max: 4 },
),
options: checkbox_options,
};

case FieldTypes.DROPDOWN:
const dropdown_options = Array.from(
{ length: faker.number.int({ min: 1, max: 4 }) },
() => ({ id: faker.string.uuid(), text: faker.music.songName() }),
);
return {
...baseField,
type: FieldTypes.DROPDOWN,
value: faker.helpers.arrayElements(
dropdown_options.map((o) => o.id),
1,
),
options: dropdown_options,
};

case FieldTypes.MULTIPLE_CHOICE:
const multiple_options = Array.from(
{ length: faker.number.int({ min: 1, max: 4 }) },
() => ({ id: faker.string.uuid(), text: faker.music.songName() }),
);
return {
...baseField,
type: FieldTypes.MULTIPLE_CHOICE,
value: faker.helpers.arrayElements(
multiple_options.map((o) => o.id),
1,
),
options: multiple_options,
};

default:
if (
Object.values(NormalFieldTypes).includes(fieldType as NormalFieldTypes)
) {
return {
...baseField,
type: fieldType as NormalFieldTypes,
value: faker.lorem.sentence(),
};
}
throw new Error("Unknown field type");
}
}
15 changes: 13 additions & 2 deletions lib/faker/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,33 @@ import db from "../../server/db";
import { generateUsers } from "./user";
import { generateOpportunities } from "./opportunities";
import { options } from "./utils";
import { generateApplications } from "./applications";

const numberOfOpportunities = parseInt(options.opportunities, 10);
const numberOfUsers = parseInt(options.users, 10);

try {
await db.$connect;

const generatedUsers = await generateUsers(numberOfUsers);
console.log(
`${numberOfUsers} users generated: `,
`${numberOfUsers} users generated:`,
generatedUsers.map((u) => u.name),
);

const opportunities = await generateOpportunities(numberOfOpportunities);
console.log(
`${numberOfOpportunities} opportunities generated: `,
`${numberOfOpportunities} opportunities generated:`,
opportunities.map((o) => o.generalInformation.title),
);

const opportunityIds = opportunities.map((o) => o.id!);

const applications = await generateApplications(opportunityIds);
console.log(
`${applications.length} applications generated:`,
applications.map((a) => a.content.eventId),
);
} catch (error) {
await db.$disconnect();
console.error(error);
Expand Down
12 changes: 10 additions & 2 deletions lib/faker/opportunities.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { faker } from "@faker-js/faker";
import db from "server/db";
import { fetchAllUsers, keyUniqueEnforcer, now, options, uuidUniqueEnforcer } from "./utils";
import {
fetchAllUsers,
keyUniqueEnforcer,
now,
options,
uuidUniqueEnforcer,
} from "./utils";
import { Person } from "@lib/types/person";
import { Question } from "@lib/types/question";
import { Opportunity, Phase, Questionnaire } from "@lib/types/opportunity";
Expand Down Expand Up @@ -29,6 +35,7 @@ export async function generateOpportunities(number: number) {
for (const opportunity of opportunities) {
await db.opportunity.create({
data: {
id: opportunity.id,
title: opportunity.generalInformation.title,
description: opportunity.generalInformation.description,
start: opportunity.generalInformation.start,
Expand Down Expand Up @@ -65,6 +72,7 @@ export async function generateOpportunities(number: number) {

function generateOpportunity(): Opportunity {
return {
id: uuidUniqueEnforcer.enforce(() => faker.number.int({ max: 9999999 })),
generalInformation: generateGeneralInformation(),
phases: generatePhases(),
};
Expand Down Expand Up @@ -119,7 +127,7 @@ function generateQuestionnaire(): Questionnaire {
generateQuestion,
),
conditions: [],
reviewers: faker.helpers.arrayElements(allPersons, 2),
reviewers: allPersons,
};
}

Expand Down
9 changes: 9 additions & 0 deletions lib/faker/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ program
"-maxq, --maxquestionnaires <number>",
"maximal number of questionnaires to generate per phase",
"3",
).option(
"-mina, --minapplications <number>",
"minimal number of applications to generate per opportunity",
"1"
)
.option(
"-maxa, --maxapplications <number>",
"maximal number of applications to generate per opportunity",
"5"
)
.parse(process.argv);

Expand Down
3 changes: 1 addition & 2 deletions lib/schemas/tally.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,13 @@ export const TallyField = z
.or(z.literal("INPUT_NUMBER"))
.or(z.literal("INPUT_DATE"))
.or(z.literal("INPUT_EMAIL"))
.or(z.literal("TEXTAREA"))
.or(z.literal("INPUT_LINK")),
value: z.string().nullable(),
}),
]),
);

const TallyData = z.object({
export const TallyData = z.object({
responseId: z.string(),
submissionId: z.string(),
respondentId: z.string(),
Expand Down
3 changes: 2 additions & 1 deletion lib/types/tally.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { TallyField, TallySchema } from "@lib/schemas/tally";
import { TallyData, TallyField, TallySchema } from "@lib/schemas/tally";
import { z } from "zod";

export type Tally = z.infer<typeof TallySchema>;
export type TallyData = z.infer<typeof TallyData>
export type TallyField = z.infer<typeof TallyField>;

0 comments on commit e32aa36

Please sign in to comment.