diff --git a/app/javascript/pages/assessment/NewAssessement.tsx b/app/javascript/pages/assessment/NewAssessement.tsx index 47fccbf..ba58ec8 100644 --- a/app/javascript/pages/assessment/NewAssessement.tsx +++ b/app/javascript/pages/assessment/NewAssessement.tsx @@ -5,6 +5,7 @@ import { Controller, useForm } from "react-hook-form"; import { Axis, Query } from "../../__generated__/graphql-schema"; import { Button, Card, Input, Navigator } from '../../components'; +import { useHistory } from "react-router"; type NewAssessementForm = { axisWeights: Record @@ -47,6 +48,8 @@ export const NewAssessement = () => { const notSelectedAxis: Axis[] = axes.filter((axis) => !subjectsIds.includes(axis.id)) const selectedAxis: Axis[] = axes.filter((axis) => subjectsIds.includes(axis.id)) + const navigate = useHistory() + return ( <> @@ -179,9 +182,14 @@ export const NewAssessement = () => { - +
+ + +
) } \ No newline at end of file diff --git a/app/javascript/pages/assessment/NewAssessmentManual.tsx b/app/javascript/pages/assessment/NewAssessmentManual.tsx new file mode 100644 index 0000000..b86cf40 --- /dev/null +++ b/app/javascript/pages/assessment/NewAssessmentManual.tsx @@ -0,0 +1,85 @@ +import React, { useState } from "react"; +import { Navigator } from '../../components'; +import { SelectedQuestionsSideBar } from "./components/SelectedQuestionsSideBar"; +import { FiltersSideBar } from "./components/FiltersSideBar"; +import { BottomBar } from "./components/BottomBar"; +import { QuestionArea } from "./components/QuestionArea"; +import { gql, useQuery } from "@apollo/client"; +import { Query, Question } from "../../__generated__/graphql-schema"; + +const QuestionFragments = gql` + fragment QuestionFields on Question { + id + authorship + authorshipYear + bloomTaxonomy + body + checkType + difficulty + status + subject { + axis { + name + } + category { + name + } + name + } + } +` + +const QUESTIONS_QUERY = gql` + ${QuestionFragments} + query { + questions { + nodes { + ...QuestionFields + } + } + } +` + +export const NewAssessementManual = () => { + const [questions, setQuestions] = useState([]) + const [selectedQuestions, setSelectedQuestions] = useState<{id: string, label: string, removeHandler: Function}[]>([]) + + useQuery(QUESTIONS_QUERY, { + onCompleted: (response) => { + const { questions: questionConnection } = response + setQuestions(questionConnection.nodes as Question[]) + }, + fetchPolicy: "network-only" + }) + + const addQuestion = (label: string, removeHandler: Function) => { + const id: string = label.replace(/\s+/g, '_') + if (!selectedQuestions.find(q => q.id === id)) { + setSelectedQuestions(q => [...q, { id, label, removeHandler }]) + } + } + + const removeQuestion = (id: string) => { + setSelectedQuestions(q => q.filter(i => i.id !== id)) + } + + const clearSelectedQuestions = () => { + setSelectedQuestions([]) + } + + return ( + <> + + +
+ + + +
+ + ) +} \ No newline at end of file diff --git a/app/javascript/pages/assessment/components/BottomBar.tsx b/app/javascript/pages/assessment/components/BottomBar.tsx new file mode 100644 index 0000000..91502e5 --- /dev/null +++ b/app/javascript/pages/assessment/components/BottomBar.tsx @@ -0,0 +1,21 @@ +import React, { FC, } from "react"; +import { Button } from "../../../components"; + +type Props = { + +} + +export const BottomBar: FC = () => { + return ( +
+
+ + +
+
+ ) +} \ No newline at end of file diff --git a/app/javascript/pages/assessment/components/FiltersSideBar.tsx b/app/javascript/pages/assessment/components/FiltersSideBar.tsx new file mode 100644 index 0000000..8cba45a --- /dev/null +++ b/app/javascript/pages/assessment/components/FiltersSideBar.tsx @@ -0,0 +1,94 @@ +import React, { FC, useState, } from "react"; +import { SideBar } from "./SideBar"; +import { Button } from "../../../components"; +import { SelectFilterField } from "./SelectFilterField"; +import { RangeFilterField } from "./RangeFilterField"; +import { BLOOM_TAXONOMY, CHECK_TYPE, DIFFICULTY } from "../../../utils/types"; +import { gql, useQuery } from "@apollo/client"; +import { Axis, Category, Query, Subject } from "../../../__generated__/graphql-schema"; + +const FILTERS_QUERY = gql` + query { + categories { + nodes { + id + name + } + } + axes { + nodes { + id + name + } + } + subjects { + nodes { + id + name + } + } + } +` + +type Props = { + +} + +export const FiltersSideBar: FC = () => { + const [categories, setCategories] = useState([]) + const [axis, setAxis] = useState([]) + const [subjects, setSubjects] = useState([]) + + const difficulties = DIFFICULTY.map(item => ({id: item.value, label: item.label})) + const bloomTaxonomyTypes = BLOOM_TAXONOMY.map(item => ({id: item.value, label: item.label})) + const checkTypes = CHECK_TYPE.map(item => ({id: item.value, label: item.label})) + const authorshipTypes = [ + {id: 1, label: 'Própria'}, + {id: 2, label: 'Outro'}, + ] + + useQuery(FILTERS_QUERY, { + onCompleted: (response) => { + const { + categories: categoriesConnection, + axes: axisConnection, + subjects: subjectConnection + } = response + setCategories(categoriesConnection.nodes as Category[]) + setAxis(axisConnection.nodes as Axis[]) + setSubjects(subjectConnection.nodes as Subject[]) + }, + fetchPolicy: "network-only" + }) + + return ( + +
+
+ + ({id: item.id, label: item.name})) + }/> + ({id: item.id, label: item.name})) + }/> + ({id: item.id, label: item.name})) + }/> + + + + +
+ + +
+ +
+
+ ) +} \ No newline at end of file diff --git a/app/javascript/pages/assessment/components/QuestionArea.tsx b/app/javascript/pages/assessment/components/QuestionArea.tsx new file mode 100644 index 0000000..564ea91 --- /dev/null +++ b/app/javascript/pages/assessment/components/QuestionArea.tsx @@ -0,0 +1,20 @@ +import React, { FC } from "react"; +import { QuestionCard } from "./QuestionCard"; +import { Question } from "../../../__generated__/graphql-schema"; + +interface Props { + questions: Question[] + onAddQuestion: Function, + onRemoveQuestion: Function +} + +export const QuestionArea: FC = ({ questions, onAddQuestion, onRemoveQuestion }) => { + return ( +
+ {questions.map(question => + )} +
+ ) +} \ No newline at end of file diff --git a/app/javascript/pages/assessment/components/QuestionCard.tsx b/app/javascript/pages/assessment/components/QuestionCard.tsx new file mode 100644 index 0000000..e770e81 --- /dev/null +++ b/app/javascript/pages/assessment/components/QuestionCard.tsx @@ -0,0 +1,75 @@ +import React, { FC, useState } from "react"; +import { Button, Card } from "../../../components"; +import { QuestionCardField } from "./QuestionCardField"; +import { Question } from "../../../__generated__/graphql-schema"; +import { NodeId } from "../../../utils/graphql"; +import { BLOOM_TAXONOMY, CHECK_TYPE, DIFFICULTY } from "../../../utils/types"; + +interface Props { + question: Question + onAddQuestion: Function, + onRemoveQuestion: Function +} + +export const QuestionCard: FC = ({ question, onAddQuestion, onRemoveQuestion }) => { + const [collapsed, setCollapsed] = useState(false) + + const title = `Questão ${NodeId.decode(question.id).id}` + const htmlId = title.replace(/\s+/g, '_') + const difficulty = DIFFICULTY.find(item => item.value === question.difficulty)?.label + const bloomTaxonomy = BLOOM_TAXONOMY.find(item => item.value === question.bloomTaxonomy)?.label + const checkType = CHECK_TYPE.find(item => item.value === question.checkType)?.label + + const handleAddQuestion = () => { + setButtonState({ + bg: 'bg-red-700', label: 'Remover', method: handleRemoveQuestion + }) + onAddQuestion(title, handleRemoveQuestion) + } + + const handleRemoveQuestion = () => { + setButtonState({ + bg: '', label: 'Adicionar', method: handleAddQuestion + }) + onRemoveQuestion(htmlId) + } + + const [buttonState, setButtonState] = useState({ + bg: '', label: 'Adicionar', method: handleAddQuestion + }) + + return ( +
+ +
+ {!collapsed &&
+ + + + + + + + +
+ Enunciado: +
+
+
} +
+
+
+ + +
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/app/javascript/pages/assessment/components/QuestionCardField.tsx b/app/javascript/pages/assessment/components/QuestionCardField.tsx new file mode 100644 index 0000000..989886b --- /dev/null +++ b/app/javascript/pages/assessment/components/QuestionCardField.tsx @@ -0,0 +1,16 @@ +import React, { FC } from "react"; +import { Maybe } from "../../../__generated__/graphql-schema"; + +interface Props { + label: string, + value?: Maybe +} + +export const QuestionCardField: FC = ({ label, value }) => { + return ( +
+ {`${label}: `} + {value ?? ''} +
+ ) +} \ No newline at end of file diff --git a/app/javascript/pages/assessment/components/RangeFilterField.tsx b/app/javascript/pages/assessment/components/RangeFilterField.tsx new file mode 100644 index 0000000..8dbff06 --- /dev/null +++ b/app/javascript/pages/assessment/components/RangeFilterField.tsx @@ -0,0 +1,23 @@ +import React, { FC, } from "react"; + +type Props = { + label: string +} + +export const RangeFilterField: FC = ({ label }) => { + return ( +
+ {label} +
+
+ Início + +
+
+ Fim + +
+
+
+ ) +} \ No newline at end of file diff --git a/app/javascript/pages/assessment/components/SelectFilterField.tsx b/app/javascript/pages/assessment/components/SelectFilterField.tsx new file mode 100644 index 0000000..3a33852 --- /dev/null +++ b/app/javascript/pages/assessment/components/SelectFilterField.tsx @@ -0,0 +1,19 @@ +import React, { FC, } from "react"; + +type Props = { + options: {id: number | string, label: string,}[] + label: string +} + +export const SelectFilterField: FC = ({ options, label }) => { + return ( +
+ {label} + +
+ ) +} \ No newline at end of file diff --git a/app/javascript/pages/assessment/components/SelectedQuestionCard.tsx b/app/javascript/pages/assessment/components/SelectedQuestionCard.tsx new file mode 100644 index 0000000..a685688 --- /dev/null +++ b/app/javascript/pages/assessment/components/SelectedQuestionCard.tsx @@ -0,0 +1,27 @@ +import React, { FC } from 'react'; +import { FaTrash } from 'react-icons/fa'; + +type Props = { + label: string + id: string + onRemoveQuestion: Function +} + +export const SelectedQuestionCard: FC = ({ label, id, onRemoveQuestion }) => { + return ( +
+ +

{`# ${label ?? id}`}

+
+
+ +
+
+ ) +} + diff --git a/app/javascript/pages/assessment/components/SelectedQuestionsSideBar.tsx b/app/javascript/pages/assessment/components/SelectedQuestionsSideBar.tsx new file mode 100644 index 0000000..78f17b5 --- /dev/null +++ b/app/javascript/pages/assessment/components/SelectedQuestionsSideBar.tsx @@ -0,0 +1,37 @@ +import React, { FC, } from "react"; +import { SideBar } from "./SideBar"; +import { SelectedQuestionCard } from "./SelectedQuestionCard"; +import { Button } from "../../../components"; + +type Props = { + questions: { + id: string, label: string, removeHandler: Function + }[] + onClearSelectedQuestions: Function +} + +export const SelectedQuestionsSideBar: FC = ({ questions, onClearSelectedQuestions }) => { + return ( + +
+ {questions.length ? + <> +
+ {questions.map(q => )} +
+
+ +
+ : +

+ Nenhuma questão selecionada +

+ } +
+
+ ) +} \ No newline at end of file diff --git a/app/javascript/pages/assessment/components/SideBar.tsx b/app/javascript/pages/assessment/components/SideBar.tsx new file mode 100644 index 0000000..d18e403 --- /dev/null +++ b/app/javascript/pages/assessment/components/SideBar.tsx @@ -0,0 +1,20 @@ +import React, { FC, PropsWithChildren } from "react"; + +interface Props extends PropsWithChildren { + header?: string; +} + +export const SideBar: FC = ({ header, children }) => { + return ( +
+ {header && + <> +

{header}

+
+ } +
+ {children} +
+
+ ) +} \ No newline at end of file diff --git a/app/javascript/routes/paths.ts b/app/javascript/routes/paths.ts index 376de37..1318bd0 100644 --- a/app/javascript/routes/paths.ts +++ b/app/javascript/routes/paths.ts @@ -21,4 +21,5 @@ export const DashboardRoutePaths = { export const AssessmentRoutePaths = { index: "/assessments", new: "/assessments/new", + newManual: "/assessments/new-manual" } \ No newline at end of file diff --git a/app/javascript/routes/routes.tsx b/app/javascript/routes/routes.tsx index dadbf56..55ce9c5 100644 --- a/app/javascript/routes/routes.tsx +++ b/app/javascript/routes/routes.tsx @@ -3,6 +3,7 @@ import { Redirect, Route, Switch } from "react-router-dom"; import { AssessmentList } from "../pages/assessment"; import { NewAssessement } from "../pages/assessment/NewAssessement"; +import { NewAssessementManual } from "../pages/assessment/NewAssessmentManual"; import { Dashboard } from '../pages/dashboard'; import { Edit, List, New, Review, Show } from "../pages/question"; import { Profile } from "../pages/session"; @@ -22,5 +23,6 @@ export const PrivateRoutes = () => ( + );