Skip to content
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"type-css:check": "npx tcm src --listDifferent",
"test": "next build --no-lint && ava",
"test-storybook": "test-storybook --maxWorkers=2",
"docker-reup": "docker compose -f supporting_services/docker-compose.yml up -d",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to add this script!

"db:migrate": "npx tsx src/backend/scripts/migrate-database.ts",
"db:reset": "npx tsx src/backend/scripts/reset-database.ts",
"db:seed": "npx tsx src/backend/scripts/seed-database.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/backend/routers/iep.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ test("basic flow - add/get goals, benchmarks, tasks", async (t) => {
const gotBenchmark = await trpc.iep.getBenchmark.query({
benchmark_id: benchmark2Id,
});
t.is(gotBenchmark[0].description, "benchmark 2");
t.is(gotBenchmark.description, "benchmark 2");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏


// TODO: Don't query db directly and use an API method instead. Possibly create a getTasks method later
t.truthy(
Expand Down
77 changes: 75 additions & 2 deletions src/backend/routers/iep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,14 +363,87 @@ export const iep = router({
.query(async (req) => {
const { benchmark_id } = req.input;

// NOTE: existing code
const result = await req.ctx.db
.selectFrom("benchmark")
.innerJoin("task", "benchmark.benchmark_id", "task.benchmark_id")
.innerJoin("user", "task.assignee_id", "user.user_id")
.where("benchmark.benchmark_id", "=", benchmark_id)
.selectAll()
.execute();
.select((eb) => [
"benchmark.description",
"benchmark.instructions",
"benchmark.frequency",
"benchmark.number_of_trials",
"benchmark.benchmark_id",
jsonArrayFrom(
eb
.selectFrom("user")
.selectAll()
.whereRef("task.assignee_id", "=", "user.user_id")
.orderBy("user.first_name")
).as("assignees"),
])
.executeTakeFirstOrThrow();
return result;
}),

//.innerJoin("task", "benchmark.benchmark_id", "task.benchmark_id")
// .innerJoin("goal", "benchmark.goal_id", "goal.goal_id")
// .innerJoin("iep", "goal.iep_id", "iep.iep_id")
// .innerJoin("student", "iep.student_id", "student.student_id")

// "task.task_id",
// "student.first_name",
// "student.last_name",
// "goal.category",
// "benchmark.description",
// "benchmark.instructions",
// "benchmark.frequency",
// "benchmark.number_of_trials",
// "benchmark.benchmark_id",
// "task.due_date",
// "task.seen",
// "task.trial_count",

// .select([
// "benchmark.description",
// "benchmark.instructions",
// "benchmark.frequency",
// "benchmark.number_of_trials",
// "benchmark.benchmark_id",
// ])

// {
// benchmark: {
// id,
// title,
// desc,
// assignees: [
// { id:, name }
// ]
// }
// }

// jsonArrayFrom(
// eb
// .selectFrom("trial_data")
// .select([
// "trial_data.trial_data_id",
// "trial_data.success",
// "trial_data.unsuccess",
// "trial_data.submitted",
// "trial_data.notes",
// "trial_data.created_at",
// ])
// .whereRef("trial_data.task_id", "=", "task.task_id")
// .whereRef(
// "trial_data.created_by_user_id",
// "=",
// "task.assignee_id"
// )
// .orderBy("trial_data.created_at")
// ).as("assignees"),

getBenchmarkByAssignee: hasCaseManager
.input(
z.object({
Expand Down
10 changes: 9 additions & 1 deletion src/client/lib/trpc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { createTRPCReact } from "@trpc/react-query";
import {
createTRPCReact,
type inferReactQueryProcedureOptions,
} from "@trpc/react-query";
import type { inferRouterInputs, inferRouterOutputs } from "@trpc/server";
import { AppRouter } from "@/backend/routers/_app";

export type ReactQueryOptions = inferReactQueryProcedureOptions<AppRouter>;
export type RouterInputs = inferRouterInputs<AppRouter>;
export type RouterOutputs = inferRouterOutputs<AppRouter>;

export const trpc = createTRPCReact<AppRouter>();
110 changes: 110 additions & 0 deletions src/components/benchmarks/BenchmarkAssignment.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { trpc } from "@/client/lib/trpc";
import { useState, useRef } from "react";

import { AssignmentDuration } from "./Duration-Selection-Step";
import { BenchmarkAssignmentModal } from "@/components/benchmarks/BenchmarkAssignmentModal";

interface BenchmarkAssignmentProps {
isOpen: boolean;
onClose: () => void;
benchmark_id: string;
}

export const STEPS = ["PARA_SELECTION", "DURATION_SELECTION"];
export type Step = (typeof STEPS)[number];

export const BenchmarkAssignment = (props: BenchmarkAssignmentProps) => {
const [selectedParaIds, setSelectedParaIds] = useState<string[]>([]);
const nextButtonRef = useRef<HTMLButtonElement>(null);
const [assignmentDuration, setAssignmentDuration] =
useState<AssignmentDuration>({ type: "forever" });
const [currentModalSelection, setCurrentModalSelection] =
useState<Step>("PARA_SELECTION");
const { data: myParas } = trpc.case_manager.getMyParas.useQuery();
const { data: benchmark } = trpc.iep.getBenchmark.useQuery({
benchmark_id: props.benchmark_id,
}); // maybe it should include assignments, or have a flag to include assignments

const [errorMessage, setErrorMessage] = useState<string>("");

const assignTaskToPara = trpc.iep.assignTaskToParas.useMutation();

const handleParaToggle = (paraId: string) => () => {
setErrorMessage("");
setSelectedParaIds((prev) => {
if (prev.includes(paraId)) {
return prev.filter((id) => id !== paraId);
} else {
return [...prev, paraId];
}
});
};

const handleClose = () => {
props.onClose();
setSelectedParaIds([]);
setErrorMessage("");
setCurrentModalSelection("PARA_SELECTION");
};

const handleBack = () => {
const currentStepIndex = STEPS.indexOf(currentModalSelection);
const previousStep = STEPS[currentStepIndex - 1];
if (previousStep) {
setCurrentModalSelection(previousStep);
}
};

const handleNext = async () => {
if (nextButtonRef.current) {
nextButtonRef.current.blur();
}
const currentStepIndex = STEPS.indexOf(currentModalSelection);
const nextStep = STEPS[currentStepIndex + 1];
if (nextStep) {
setCurrentModalSelection(nextStep);
} else {
// Reached end, save
try {
await assignTaskToPara.mutateAsync({
benchmark_id: props.benchmark_id,
para_ids: selectedParaIds,
due_date:
assignmentDuration.type === "until_date"
? assignmentDuration.date
: undefined,
trial_count:
assignmentDuration.type === "minimum_number_of_collections"
? assignmentDuration.minimumNumberOfCollections
: undefined,
});
handleClose();
} catch (err) {
// TODO: issue #450
console.log(err);
if (err instanceof Error) {
setErrorMessage(err.message);
}
}
}
};

return (
<BenchmarkAssignmentModal
isOpen={props.isOpen}
handleClose={handleClose}
benchmark={benchmark}
myParas={myParas}
currentModalSelection={currentModalSelection}
errorMessage={errorMessage}
selectedParaIds={selectedParaIds}
handleParaToggle={handleParaToggle}
assignmentDuration={assignmentDuration}
setAssignmentDuration={setAssignmentDuration}
isAssignTaskToParaLoading={assignTaskToPara.isLoading}
handleBack={handleBack}
handleNext={handleNext}
nextButtonRef={nextButtonRef}
/>
);
};
Loading