move move frontend to progress-test
This commit is contained in:
35
app/javascript/pages/question/List/List.tsx
Normal file
35
app/javascript/pages/question/List/List.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import React, { FC, useState } from "react";
|
||||
import { FaFilter } from "react-icons/fa";
|
||||
|
||||
import { Navigator } from "../../../components";
|
||||
import { QuestionsFilter } from "./QuestionFilter";
|
||||
import { QuestionsPainel } from "./QuestionsPainel";
|
||||
import { FiltersProvider } from './QuestionFilter/QuestionsFilterProvider'
|
||||
|
||||
export const List: FC = () => {
|
||||
const [filterOpen, setFilterOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<FiltersProvider>
|
||||
<Navigator newQuestion={true}>
|
||||
<li className={"hover:text-white ml-auto"}>
|
||||
<button onClick={() => setFilterOpen(true)} className="flex">
|
||||
<FaFilter className="my-auto" />
|
||||
<span className="pl-3">Filtros</span>
|
||||
</button>
|
||||
</li>
|
||||
</Navigator>
|
||||
<QuestionsFilter
|
||||
isOpen={filterOpen}
|
||||
setIsOpen={setFilterOpen}
|
||||
/>
|
||||
<div className="bg-gray-100 w-full">
|
||||
<main className="sm:px-8 rounded-t-xlg">
|
||||
<div className="mx-2 sm:mx-0 sm:mr-4">
|
||||
<QuestionsPainel />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</FiltersProvider>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
import React, { Dispatch, FC, SetStateAction } from "react";
|
||||
|
||||
type Props = {
|
||||
setChanged: Dispatch<SetStateAction<boolean>>
|
||||
register: any
|
||||
}
|
||||
|
||||
export const AuthorshipFilter: FC<Props> = ({ setChanged, register }) => {
|
||||
const options = [
|
||||
{
|
||||
label: "Qualquer",
|
||||
value: 'null'
|
||||
},
|
||||
{
|
||||
label: "Própria",
|
||||
value: 'true'
|
||||
},
|
||||
{
|
||||
label: "Terceiro",
|
||||
value: 'false',
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="mt-2 sm:mt-0 flex flex-col">
|
||||
<h3 className="font-bold mb-1">Autoria</h3>
|
||||
<div
|
||||
className="grid grid-cols-2 sm:flex sm:flex-col"
|
||||
key={`filter-group-authorship`}
|
||||
>
|
||||
{options.map(({ value, label }, index) => (
|
||||
<span className="mr-1 mb-2 sm:mb-0 sm:mr-0" key={label}>
|
||||
<input
|
||||
ref={register}
|
||||
type="radio"
|
||||
name="authorship"
|
||||
value={value}
|
||||
id={value}
|
||||
defaultChecked={!index}
|
||||
/>
|
||||
<label htmlFor={value} className="ml-2">
|
||||
{label}
|
||||
</label>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import React, { Dispatch, FC, SetStateAction } from 'react'
|
||||
|
||||
import { range } from '../../../../utils/math'
|
||||
import { useFiltersProvider } from './QuestionsFilterProvider'
|
||||
|
||||
type Props = {
|
||||
register: any
|
||||
setChanged: Dispatch<SetStateAction<boolean>>
|
||||
}
|
||||
|
||||
const CURRENT_YEAR = new Date().getFullYear()
|
||||
|
||||
const YEARS = range(1900, CURRENT_YEAR + 1).reverse()
|
||||
|
||||
export const QuestionsAuthorshipTypeFilter: FC<Props> = ({ register, setChanged }) => {
|
||||
const { where } = useFiltersProvider()
|
||||
|
||||
return (
|
||||
<div>
|
||||
<select
|
||||
ref={register}
|
||||
className="w-full rounded p-1 border-gray-400 border shadow-sm"
|
||||
name="authorshipYear"
|
||||
defaultValue={where.authorshipYear ?? ""}
|
||||
onClick={() => setChanged(true)}
|
||||
>
|
||||
<option value="" />
|
||||
{YEARS.map((year) => (
|
||||
<option
|
||||
key={`questionYear-${year}`}
|
||||
value={year}
|
||||
>
|
||||
{year}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
import React, { Dispatch, FC, SetStateAction, useRef, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import {
|
||||
QuestionBloomTaxonomy,
|
||||
QuestionCheckType,
|
||||
QuestionDifficulty,
|
||||
} from "../../../../__generated__/graphql-schema";
|
||||
import { CHECK_TYPE, BLOOM_TAXONOMY, DIFFICULTY } from "../../../../utils/types";
|
||||
|
||||
import { Button, Modal } from "../../../../components";
|
||||
import { useFiltersProvider } from "./QuestionsFilterProvider";
|
||||
import { QuestionsSubjectFilter } from './QuestionsSubjectFilter'
|
||||
import { QuestionsAuthorshipTypeFilter } from "./QuestionsAuthorshipTypeFilter";
|
||||
import { AuthorshipFilter } from "./AuthorshipFilter";
|
||||
|
||||
type FilterGroupProps = {
|
||||
title: string;
|
||||
register: any;
|
||||
options: {
|
||||
value: string;
|
||||
label: string;
|
||||
}[];
|
||||
selecteds: any[];
|
||||
setChanged: Dispatch<SetStateAction<boolean>>;
|
||||
};
|
||||
|
||||
const FilterGroup: FC<FilterGroupProps> = ({
|
||||
title,
|
||||
options,
|
||||
register,
|
||||
selecteds,
|
||||
setChanged,
|
||||
}) => (
|
||||
<>
|
||||
<div className="mt-2 sm:mt-0 flex flex-col">
|
||||
<h3 className="font-bold mb-1">{title}</h3>
|
||||
<div
|
||||
className="grid grid-cols-2 sm:flex sm:flex-col"
|
||||
key={`filter-group-${title}`}
|
||||
>
|
||||
{options.map(({ value, label }) => (
|
||||
<span className="mr-1 mb-2 sm:mb-0 sm:mr-0" key={value}>
|
||||
<input
|
||||
type="checkbox"
|
||||
name={value}
|
||||
ref={register}
|
||||
id={value}
|
||||
defaultChecked={selecteds.includes(value)}
|
||||
onClick={() => setChanged(true)}
|
||||
/>
|
||||
<label htmlFor={value} className="ml-2">
|
||||
{label}
|
||||
</label>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean;
|
||||
setIsOpen: (state: boolean) => void;
|
||||
};
|
||||
|
||||
export const QuestionsFilter: FC<Props> = ({ isOpen, setIsOpen }) => {
|
||||
const { handleSubmit, register, reset } = useForm();
|
||||
const { where, setWhere } = useFiltersProvider();
|
||||
const { difficulty, checkType, bloomTaxonomy } = where;
|
||||
const [changed, setChanged] = useState(false);
|
||||
const submitRef = useRef<HTMLInputElement>()
|
||||
|
||||
const onSubmit = (inputs: any) => {
|
||||
const valuesFromCheckType = CHECK_TYPE.filter(
|
||||
({ value }) => inputs[value]
|
||||
).map(({ value }) => value) as QuestionCheckType[];
|
||||
|
||||
const valuesFromBloomTaxonomy = BLOOM_TAXONOMY.filter(
|
||||
({ value }) => inputs[value]
|
||||
).map(({ value }) => value) as QuestionBloomTaxonomy[];
|
||||
|
||||
const valuesFromDifficulty = DIFFICULTY.filter(
|
||||
({ value }) => inputs[value]
|
||||
).map(({ value }) => value) as QuestionDifficulty[];
|
||||
|
||||
const removeKeysWithUndefiend = (obj: any) => {
|
||||
for (var propName in obj) {
|
||||
if (obj[propName] === null || obj[propName] === undefined) {
|
||||
delete obj[propName];
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
setWhere({
|
||||
unifesoAuthorship: inputs.authorship === 'null' ? null : inputs.authorship === 'true',
|
||||
...removeKeysWithUndefiend({
|
||||
checkType: valuesFromCheckType.length ? valuesFromCheckType : undefined,
|
||||
bloomTaxonomy: valuesFromBloomTaxonomy.length
|
||||
? valuesFromBloomTaxonomy
|
||||
: undefined,
|
||||
difficulty: valuesFromDifficulty.length
|
||||
? valuesFromDifficulty
|
||||
: undefined,
|
||||
subjectId: inputs.subjectId === "" ? undefined : inputs.subjectId,
|
||||
authorshipYear: inputs.authorshipYear === "" ? undefined : [inputs.authorshipYear],
|
||||
}),
|
||||
});
|
||||
|
||||
setChanged(false);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
const handleClean = () => {
|
||||
setChanged(false);
|
||||
setWhere({});
|
||||
reset();
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="Filtros"
|
||||
setIsOpen={setIsOpen}
|
||||
isOpen={isOpen}
|
||||
buttons={
|
||||
<>
|
||||
<Button
|
||||
onClick={() => handleClean()}
|
||||
disabled={!changed}
|
||||
className={`${changed ? 'opacity-1' : 'opacity-0'}`}
|
||||
>
|
||||
Limpar
|
||||
</Button>
|
||||
<Button onClick={() => setIsOpen(false)}>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button type="primary" onClick={() => submitRef.current?.click()}>
|
||||
Aplicar
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="grid grid-cols-1 gap-4 sm:gap-8 lg:grid-cols-2">
|
||||
<div className="mt-2 sm:mt-0 flex flex-col">
|
||||
<h3 className="font-bold mb-1">Assunto</h3>
|
||||
<div className="grid grid-cols-2 sm:flex sm:flex-col">
|
||||
<QuestionsSubjectFilter register={register} setChanged={setChanged} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2 sm:mt-0 flex flex-col">
|
||||
<h3 className="font-bold mb-1">Ano</h3>
|
||||
<div className="grid grid-cols-2 sm:flex sm:flex-col">
|
||||
<QuestionsAuthorshipTypeFilter register={register} setChanged={setChanged} />
|
||||
</div>
|
||||
</div>
|
||||
<FilterGroup
|
||||
title="Tipo"
|
||||
register={register}
|
||||
options={CHECK_TYPE}
|
||||
selecteds={(checkType ?? []) as QuestionCheckType[]}
|
||||
setChanged={setChanged}
|
||||
/>
|
||||
<FilterGroup
|
||||
title="Habilidade Cognitiva"
|
||||
register={register}
|
||||
options={BLOOM_TAXONOMY}
|
||||
selecteds={(bloomTaxonomy ?? []) as QuestionBloomTaxonomy[]}
|
||||
setChanged={setChanged}
|
||||
/>
|
||||
<FilterGroup
|
||||
title="Grau de Dificuldade"
|
||||
register={register}
|
||||
options={DIFFICULTY}
|
||||
selecteds={(difficulty ?? []) as QuestionDifficulty[]}
|
||||
setChanged={setChanged}
|
||||
/>
|
||||
<AuthorshipFilter register={register} setChanged={setChanged} />
|
||||
<input hidden type="submit" ref={submitRef as any} />
|
||||
</div>
|
||||
</form>
|
||||
</Modal >
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
import React, {
|
||||
createContext,
|
||||
useState,
|
||||
useMemo,
|
||||
FC,
|
||||
useContext,
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
} from 'react'
|
||||
|
||||
import { QuestionWhereInput } from '../../../../__generated__/graphql-schema'
|
||||
|
||||
type ProviderValue = {
|
||||
where: QuestionWhereInput
|
||||
setWhere: Dispatch<SetStateAction<QuestionWhereInput>>
|
||||
}
|
||||
|
||||
const FiltersContext = createContext<ProviderValue | null>(null)
|
||||
|
||||
export const useFiltersProvider = () => {
|
||||
const context = useContext(FiltersContext)
|
||||
|
||||
if (context === null) {
|
||||
throw new Error('You probably forgot to put <FiltersProvider>.')
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
export const FiltersProvider: FC = ({ children }) => {
|
||||
const [where, setWhere] = useState<QuestionWhereInput>({})
|
||||
|
||||
const providerValue = useMemo(() => ({ where, setWhere }), [
|
||||
where,
|
||||
setWhere,
|
||||
])
|
||||
|
||||
return (
|
||||
<FiltersContext.Provider value={providerValue}>
|
||||
{children}
|
||||
</FiltersContext.Provider>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import React, { Dispatch, FC, SetStateAction } from 'react'
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
|
||||
import { Query } from '../../../../__generated__/graphql-schema'
|
||||
import { useFiltersProvider } from './QuestionsFilterProvider'
|
||||
|
||||
const SUBJECTS_QUERY = gql`
|
||||
query {
|
||||
subjects {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
type Props = {
|
||||
register: any
|
||||
setChanged: Dispatch<SetStateAction<boolean>>
|
||||
}
|
||||
|
||||
export const QuestionsSubjectFilter: FC<Props> = ({ register, setChanged }) => {
|
||||
const { where } = useFiltersProvider();
|
||||
const { loading, data } = useQuery<Query>(SUBJECTS_QUERY)
|
||||
|
||||
if (loading) return null
|
||||
|
||||
const subjects = data?.subjects.nodes
|
||||
|
||||
return (
|
||||
<div>
|
||||
<select
|
||||
ref={register}
|
||||
className="w-full rounded p-1 border-gray-400 border shadow-sm"
|
||||
name="subjectId"
|
||||
defaultValue={where.subjectId ?? ""}
|
||||
onClick={() => setChanged(true)}
|
||||
>
|
||||
<option value="" />
|
||||
{subjects?.map((subject) => (
|
||||
<option
|
||||
key={`${subject?.name}-${subject?.id}`}
|
||||
value={subject?.id}
|
||||
>
|
||||
{subject?.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./QuestionsFilter";
|
||||
export * from "./QuestionsFilterProvider";
|
||||
131
app/javascript/pages/question/List/QuestionsList.tsx
Normal file
131
app/javascript/pages/question/List/QuestionsList.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
import React, { FC, useState } from 'react'
|
||||
import { FaArrowLeft, FaArrowRight } from 'react-icons/fa';
|
||||
import { MdModeEdit } from 'react-icons/md';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Question, QuestionStatus } from '../../../__generated__/graphql-schema'
|
||||
import { useCurrentUser } from '../../../contexts';
|
||||
import { NodeId } from '../../../utils/graphql';
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
const EditIcon = styled(MdModeEdit)`
|
||||
margin: auto;
|
||||
font-size: 1.5rem;
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
questions: Question[]
|
||||
title: string
|
||||
pagination?: {
|
||||
onNextPageClick: () => void
|
||||
hasNextPage: boolean
|
||||
hasPreviousPage: boolean
|
||||
onPreviousPageClick: () => void
|
||||
}
|
||||
}
|
||||
|
||||
export const QuestionsListFragments = gql`
|
||||
fragment QuestionFields on Question {
|
||||
id
|
||||
status
|
||||
user {
|
||||
id
|
||||
}
|
||||
updatedAt
|
||||
}
|
||||
`
|
||||
|
||||
export const QuestionsList: FC<Props> = ({ questions, title, pagination }) => {
|
||||
const { user } = useCurrentUser()
|
||||
const [pageCount, setPageCount] = useState(1)
|
||||
|
||||
const formatDate = (stringDate: string) => new Date(stringDate).toLocaleDateString()
|
||||
|
||||
const handleOnNextPageClick = () => {
|
||||
if (pagination?.hasNextPage) {
|
||||
pagination.onNextPageClick()
|
||||
setPageCount(pageCount + 1)
|
||||
}
|
||||
}
|
||||
const handleOnPreviousPageClick = () => {
|
||||
if (pagination?.hasPreviousPage) {
|
||||
pagination.onPreviousPageClick()
|
||||
setPageCount(pageCount - 1)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-gray-200 p-4 rounded my-2">
|
||||
<div className="flex">
|
||||
<h2 className="text-gray-500 font-medium text-xl">{title}</h2>
|
||||
<div className="ml-auto text-sm sm:text-base text-gray-700">
|
||||
<button
|
||||
className="p-2"
|
||||
onClick={handleOnPreviousPageClick}
|
||||
style={{ visibility: (pagination?.hasPreviousPage ? 'visible' : 'hidden') }}
|
||||
>
|
||||
<FaArrowLeft />
|
||||
</button>
|
||||
Página: {pageCount}
|
||||
<button
|
||||
className="p-2"
|
||||
onClick={handleOnNextPageClick}
|
||||
style={{ visibility: (pagination?.hasNextPage ? 'visible' : 'hidden') }}
|
||||
>
|
||||
<FaArrowRight />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr className="border-t border-gray-400 m-px" />
|
||||
<div className="p-2 text-sm">
|
||||
{questions.length
|
||||
? <div className="flex-col w-full sm:grid gap-4 sm:col-gap-8 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
|
||||
{questions.map((question) => (
|
||||
<div
|
||||
key={`question-${question.id}`}
|
||||
className="mx-1 sm:mx-0 mb-4 sm:mb-0 border-l-8 border-primary-light flex bg-white hover:bg-unifeso-50 rounded shadow hover:shadow-md cursor-pointer group transition-all duration-500"
|
||||
>
|
||||
<Link
|
||||
className="flex flex-col w-full px-3 py-2"
|
||||
to={`/questions/${question.id}/${(question.user.id === user?.id ? '' : 'review')}`}
|
||||
>
|
||||
<h2>
|
||||
{`# ${NodeId.decode(question.id).id}`}
|
||||
</h2>
|
||||
<div className="text-sm text-gray-700 flex flex-col flex-wrap justify-between">
|
||||
<span>
|
||||
Atualizada em:
|
||||
{" "}
|
||||
{formatDate(question.updatedAt)}
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
{(question.user.id === user?.id && question.status !== QuestionStatus.Registered) &&
|
||||
<div
|
||||
className="flex flex-col relative flex-grow justify-center"
|
||||
>
|
||||
<Link
|
||||
className="group-hover:block absolute bg-gray-300 hover:bg-primary-normal text-gray-500 hover:text-gray-100 hover:shadow-lg rounded-full p-2 cursor-pointer shadow-inner transition-all duration-500"
|
||||
style={{ left: '-1.5rem' }}
|
||||
to={`/questions/${question.id}/edit`}
|
||||
>
|
||||
<EditIcon />
|
||||
</Link>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
: <div className="grid text-gray-800" style={{ placeItems: 'center' }}>
|
||||
<div className="text-center">
|
||||
<span className="text-sm sm:text-base">
|
||||
Nenhuma questão.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
22
app/javascript/pages/question/List/QuestionsPainel.tsx
Normal file
22
app/javascript/pages/question/List/QuestionsPainel.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import React, { FC } from 'react'
|
||||
import { QuestionStatus } from '../../../__generated__/graphql-schema'
|
||||
import { useFiltersProvider } from './QuestionFilter/QuestionsFilterProvider'
|
||||
import { QuestionsQuery } from './QuestionsQuery'
|
||||
import { QuestionsRevisedQuery } from './QuestionsRevisedQuery'
|
||||
import { QuestionsWaitingReviewQuery } from './QuestionsWaitingReviewQuery'
|
||||
|
||||
export const QuestionsPainel: FC = () => {
|
||||
const { where } = useFiltersProvider()
|
||||
|
||||
return (
|
||||
<>
|
||||
<QuestionsWaitingReviewQuery title="Aguardando seu Parecer" />
|
||||
<QuestionsQuery title="Aguardando Parecer do Revisor" where={where} status={QuestionStatus.WaitingReview} />
|
||||
<QuestionsQuery title="Pendentes de Alterações" where={where} status={QuestionStatus.WithRequestedChanges} />
|
||||
<QuestionsQuery title="Rascunhos" where={where} status={QuestionStatus.Draft} />
|
||||
<QuestionsQuery title="Aprovadas" where={where} status={QuestionStatus.Approved} />
|
||||
<QuestionsQuery title="Registradas" where={where} status={QuestionStatus.Registered} />
|
||||
<QuestionsRevisedQuery title="Revisadas por Você" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
95
app/javascript/pages/question/List/QuestionsQuery.tsx
Normal file
95
app/javascript/pages/question/List/QuestionsQuery.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import React, { FC, useState } from 'react'
|
||||
|
||||
import { PageInfo, Query, Question, QuestionWhereInput, QuestionStatus } from '../../../__generated__/graphql-schema';
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import { QuestionsList, QuestionsListFragments } from './QuestionsList'
|
||||
import { useCurrentUser } from '../../../contexts';
|
||||
|
||||
const QUESTIONS_QUERY = gql`
|
||||
${QuestionsListFragments}
|
||||
query QuestionsQuery($first: Int!, $after: String, $before: String, $where: QuestionWhereInput) {
|
||||
questions (
|
||||
first: $first,
|
||||
after: $after,
|
||||
before: $before,
|
||||
where: $where
|
||||
) {
|
||||
nodes {
|
||||
... QuestionFields
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
const PAGE_SIZE = 4
|
||||
|
||||
type Props = {
|
||||
title: string
|
||||
where?: QuestionWhereInput
|
||||
status?: QuestionStatus
|
||||
}
|
||||
|
||||
export const QuestionsQuery: FC<Props> = ({ title, where, status }) => {
|
||||
const { user } = useCurrentUser()
|
||||
|
||||
const [questions, setQuestions] = useState<Question[]>([])
|
||||
const [pageInfo, setPageInfo] = useState<PageInfo | undefined>()
|
||||
|
||||
const updateQuestions = (queryResult: Query) => {
|
||||
const { questions: questionConnection } = queryResult
|
||||
|
||||
setQuestions(questionConnection.nodes as Question[])
|
||||
setPageInfo(questionConnection.pageInfo)
|
||||
}
|
||||
|
||||
const whereInput = {
|
||||
status,
|
||||
userId: user?.id,
|
||||
...where
|
||||
}
|
||||
|
||||
const { fetchMore } = useQuery<Query>(QUESTIONS_QUERY, {
|
||||
onCompleted: (response) => {
|
||||
updateQuestions(response)
|
||||
},
|
||||
variables: {
|
||||
first: PAGE_SIZE,
|
||||
where: whereInput,
|
||||
},
|
||||
fetchPolicy: "network-only",
|
||||
})
|
||||
|
||||
const onNextPageClick = () => {
|
||||
fetchMore({
|
||||
variables: {
|
||||
first: PAGE_SIZE,
|
||||
after: pageInfo?.endCursor,
|
||||
},
|
||||
}).then(({ data }) => {
|
||||
updateQuestions(data)
|
||||
})
|
||||
}
|
||||
|
||||
const onPreviousPageClick = () => {
|
||||
fetchMore({
|
||||
variables: {
|
||||
first: PAGE_SIZE,
|
||||
before: pageInfo?.startCursor,
|
||||
},
|
||||
}).then(({ data }) => {
|
||||
updateQuestions(data)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<QuestionsList
|
||||
title={title}
|
||||
questions={questions}
|
||||
pagination={{
|
||||
onNextPageClick: onNextPageClick,
|
||||
hasNextPage: pageInfo?.hasNextPage ?? false,
|
||||
hasPreviousPage: pageInfo?.hasPreviousPage ?? false,
|
||||
onPreviousPageClick: onPreviousPageClick
|
||||
}}
|
||||
/>
|
||||
)
|
||||
};
|
||||
89
app/javascript/pages/question/List/QuestionsRevisedQuery.tsx
Normal file
89
app/javascript/pages/question/List/QuestionsRevisedQuery.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import React, { FC, useState } from 'react'
|
||||
|
||||
import { PageInfo, Query, Question, ReviewRequest, User } from '../../../__generated__/graphql-schema';
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import { QuestionsList, QuestionsListFragments } from './QuestionsList'
|
||||
|
||||
const QUESTIONS_QUERY = gql`
|
||||
${QuestionsListFragments}
|
||||
query QuestionsRevisedQuery($first: Int!, $after: String) {
|
||||
currentUser {
|
||||
id
|
||||
inactiveReviewRequests(
|
||||
first: $first,
|
||||
after: $after
|
||||
) {
|
||||
nodes {
|
||||
id
|
||||
question {
|
||||
... QuestionFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
const PAGE_SIZE = 4
|
||||
|
||||
type Props = {
|
||||
title: string
|
||||
}
|
||||
|
||||
export const QuestionsRevisedQuery: FC<Props> = ({ title }) => {
|
||||
const [questions, setQuestions] = useState<Question[]>([])
|
||||
const [pageInfo, setPageInfo] = useState<PageInfo | undefined>()
|
||||
|
||||
const updateQuestions = (queryResult: Query) => {
|
||||
const { currentUser } = queryResult
|
||||
const { inactiveReviewRequests } = currentUser as User
|
||||
const reviewRequests = inactiveReviewRequests.nodes as ReviewRequest[]
|
||||
|
||||
setQuestions(reviewRequests.map(item => item.question))
|
||||
setPageInfo(inactiveReviewRequests.pageInfo)
|
||||
}
|
||||
|
||||
const { fetchMore } = useQuery<Query>(QUESTIONS_QUERY, {
|
||||
onCompleted: (response) => {
|
||||
updateQuestions(response)
|
||||
},
|
||||
variables: {
|
||||
first: PAGE_SIZE,
|
||||
},
|
||||
fetchPolicy: "network-only"
|
||||
})
|
||||
|
||||
const onNextPageClick = () => {
|
||||
fetchMore({
|
||||
variables: {
|
||||
first: PAGE_SIZE,
|
||||
after: pageInfo?.endCursor,
|
||||
},
|
||||
}).then(({ data }) => {
|
||||
updateQuestions(data)
|
||||
})
|
||||
}
|
||||
|
||||
const onPreviousPageClick = () => {
|
||||
fetchMore({
|
||||
variables: {
|
||||
first: PAGE_SIZE,
|
||||
before: pageInfo?.startCursor,
|
||||
},
|
||||
}).then(({ data }) => {
|
||||
updateQuestions(data)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<QuestionsList
|
||||
title={title}
|
||||
questions={questions}
|
||||
pagination={{
|
||||
onNextPageClick: onNextPageClick,
|
||||
hasNextPage: pageInfo?.hasNextPage ?? false,
|
||||
hasPreviousPage: pageInfo?.hasPreviousPage ?? false,
|
||||
onPreviousPageClick: onPreviousPageClick
|
||||
}}
|
||||
/>
|
||||
)
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
import React, { FC, useState } from 'react'
|
||||
|
||||
import { PageInfo, Query, Question, ReviewRequest, User } from '../../../__generated__/graphql-schema';
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import { QuestionsList, QuestionsListFragments } from './QuestionsList'
|
||||
|
||||
const QUESTIONS_QUERY = gql`
|
||||
${QuestionsListFragments}
|
||||
query QuestionsWaitingReviewQuery($first: Int!, $after: String) {
|
||||
currentUser {
|
||||
id
|
||||
activeReviewRequests(
|
||||
first: $first,
|
||||
after: $after
|
||||
) {
|
||||
nodes {
|
||||
id
|
||||
question {
|
||||
... QuestionFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
const PAGE_SIZE = 4
|
||||
|
||||
type Props = {
|
||||
title: string
|
||||
}
|
||||
|
||||
export const QuestionsWaitingReviewQuery: FC<Props> = ({ title }) => {
|
||||
const [questions, setQuestions] = useState<Question[]>([])
|
||||
const [pageInfo, setPageInfo] = useState<PageInfo | undefined>()
|
||||
|
||||
const updateQuestions = (queryResult: Query) => {
|
||||
const { currentUser } = queryResult
|
||||
const { activeReviewRequests } = currentUser as User
|
||||
const reviewRequests = activeReviewRequests.nodes as ReviewRequest[]
|
||||
|
||||
setQuestions(reviewRequests.map(item => item.question))
|
||||
setPageInfo(activeReviewRequests.pageInfo)
|
||||
}
|
||||
|
||||
const { fetchMore } = useQuery<Query>(QUESTIONS_QUERY, {
|
||||
onCompleted: (response) => {
|
||||
updateQuestions(response)
|
||||
},
|
||||
variables: {
|
||||
first: PAGE_SIZE,
|
||||
},
|
||||
fetchPolicy: "network-only"
|
||||
})
|
||||
|
||||
const onNextPageClick = () => {
|
||||
fetchMore({
|
||||
variables: {
|
||||
first: PAGE_SIZE,
|
||||
after: pageInfo?.endCursor,
|
||||
},
|
||||
}).then(({ data }) => {
|
||||
updateQuestions(data)
|
||||
})
|
||||
}
|
||||
|
||||
const onPreviousPageClick = () => {
|
||||
fetchMore({
|
||||
variables: {
|
||||
first: PAGE_SIZE,
|
||||
before: pageInfo?.startCursor,
|
||||
},
|
||||
}).then(({ data }) => {
|
||||
updateQuestions(data)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<QuestionsList
|
||||
title={title}
|
||||
questions={questions}
|
||||
pagination={{
|
||||
onNextPageClick: onNextPageClick,
|
||||
hasNextPage: pageInfo?.hasNextPage ?? false,
|
||||
hasPreviousPage: pageInfo?.hasPreviousPage ?? false,
|
||||
onPreviousPageClick: onPreviousPageClick
|
||||
}}
|
||||
/>
|
||||
)
|
||||
};
|
||||
1
app/javascript/pages/question/List/index.ts
Normal file
1
app/javascript/pages/question/List/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { List } from "./List";
|
||||
Reference in New Issue
Block a user