diff --git a/src/components/ContributorsSelector.tsx b/src/components/ContributorsSelector.tsx new file mode 100644 index 0000000..38f4ec9 --- /dev/null +++ b/src/components/ContributorsSelector.tsx @@ -0,0 +1,30 @@ +import { FC } from "react"; +import { UsersQuery, useUsersQuery } from "@/generated/graphql.tsx"; +import { Skeleton } from "@mui/material"; +import { MultiSelect } from "@/components/MultiSelect.tsx"; + +type ArrayElement = + ArrayType extends readonly (infer ElementType)[] ? ElementType : never; + +type ContributorsSelectorProp = { + selectedUsers: string[]; + onChange: (value: UsersQuery["users"]) => void; +}; + +export const ContributorsSelector: FC = (props) => { + const { data, loading } = useUsersQuery(); + + if (loading) return ; + if (!data) return "Failed to load users"; + + return ( + > + label="Közreműködők" + items={data.users} + value={data.users.filter((user) => props.selectedUsers.includes(user.id))} + getItemLabel={(item) => item.name} + getItemKey={(item) => item.id} + onChange={props.onChange} + /> + ); +}; diff --git a/src/components/CreatedByItem.tsx b/src/components/CreatedByItem.tsx new file mode 100644 index 0000000..ee23c40 --- /dev/null +++ b/src/components/CreatedByItem.tsx @@ -0,0 +1,20 @@ +import { User } from "@/generated/graphql.tsx"; +import { Avatar, Typography } from "@mui/material"; + +export const CreatedByItem = ({ + user, +}: { + user: Pick; +}) => { + return ( + <> + + + {user.name} + + + ); +}; diff --git a/src/generated/graphql.tsx b/src/generated/graphql.tsx index 1b4cc8e..2e0a88c 100644 --- a/src/generated/graphql.tsx +++ b/src/generated/graphql.tsx @@ -678,7 +678,7 @@ export type SelectExerciseQueryVariables = Exact<{ }>; -export type SelectExerciseQuery = { __typename: 'Query', exercise?: { __typename: 'Exercise', id: string, status: ExerciseStatus, description: string, solutionOptions: Array, solution: string, solveIdea?: string | null, source?: string | null, createdAt: string, helpingQuestions: Array, alert?: { __typename: 'ExerciseAlert', description: string, severity: AlertSeverity } | null, sameLogicExerciseGroup?: { __typename: 'SameLogicExerciseGroup', exercises: Array<{ __typename: 'Exercise', id: string, description: string, createdAt: string, difficulty: Array<{ __typename: 'ExerciseDifficulty', difficulty: number, ageGroup: ExerciseAgeGroup }>, exerciseImage?: { __typename: 'Image', url: string } | null, tags: Array<{ __typename: 'Tag', id: string, name: string }>, createdBy: { __typename: 'User', id: string, userName: string, avatarUrl?: string | null } }> } | null, exerciseImage?: { __typename: 'Image', id: string, url: string } | null, solutionImage?: { __typename: 'Image', id: string, url: string } | null, createdBy: { __typename: 'User', id: string, name: string, avatarUrl?: string | null }, solveIdeaImage?: { __typename: 'Image', id: string, url: string } | null, tags: Array<{ __typename: 'Tag', id: string, name: string }>, difficulty: Array<{ __typename: 'ExerciseDifficulty', ageGroup: ExerciseAgeGroup, difficulty: number }>, checks: Array<{ __typename: 'ExerciseCheck', id: string, type: ExerciseCheckType, createdAt: string, user: { __typename: 'User', id: string, name: string } }> } | null }; +export type SelectExerciseQuery = { __typename: 'Query', exercise?: { __typename: 'Exercise', id: string, status: ExerciseStatus, description: string, solutionOptions: Array, solution: string, solveIdea?: string | null, source?: string | null, createdAt: string, helpingQuestions: Array, alert?: { __typename: 'ExerciseAlert', description: string, severity: AlertSeverity } | null, sameLogicExerciseGroup?: { __typename: 'SameLogicExerciseGroup', exercises: Array<{ __typename: 'Exercise', id: string, description: string, createdAt: string, difficulty: Array<{ __typename: 'ExerciseDifficulty', difficulty: number, ageGroup: ExerciseAgeGroup }>, exerciseImage?: { __typename: 'Image', url: string } | null, tags: Array<{ __typename: 'Tag', id: string, name: string }>, createdBy: { __typename: 'User', id: string, userName: string, avatarUrl?: string | null } }> } | null, exerciseImage?: { __typename: 'Image', id: string, url: string } | null, solutionImage?: { __typename: 'Image', id: string, url: string } | null, createdBy: { __typename: 'User', id: string, name: string, avatarUrl?: string | null }, contributors: Array<{ __typename: 'User', id: string, name: string, avatarUrl?: string | null }>, solveIdeaImage?: { __typename: 'Image', id: string, url: string } | null, tags: Array<{ __typename: 'Tag', id: string, name: string }>, difficulty: Array<{ __typename: 'ExerciseDifficulty', ageGroup: ExerciseAgeGroup, difficulty: number }>, checks: Array<{ __typename: 'ExerciseCheck', id: string, type: ExerciseCheckType, createdAt: string, user: { __typename: 'User', id: string, name: string } }> } | null }; export type ExerciseHistoryByExerciseQueryVariables = Exact<{ exerciseId: Scalars['ID']['input']; @@ -1366,6 +1366,11 @@ export const SelectExerciseDocument = gql` name avatarUrl } + contributors { + id + name + avatarUrl + } solveIdeaImage { id url diff --git a/src/graphql/exercise.graphql b/src/graphql/exercise.graphql index cbdb8d0..8e587e0 100644 --- a/src/graphql/exercise.graphql +++ b/src/graphql/exercise.graphql @@ -65,6 +65,11 @@ query selectExercise($exerciseId: ID!) { name avatarUrl } + contributors { + id + name + avatarUrl + } solveIdeaImage { id url diff --git a/src/pages/ExerciseDetails.tsx b/src/pages/ExerciseDetails.tsx index 6f53ee2..e376f9b 100644 --- a/src/pages/ExerciseDetails.tsx +++ b/src/pages/ExerciseDetails.tsx @@ -13,7 +13,6 @@ import { ExerciseFieldsType } from "@/util/types"; import { LoadingButton } from "@mui/lab"; import { Alert, - Avatar, Button, Card, Divider, @@ -34,6 +33,7 @@ import ExerciseFields from "./createExercise/ExerciseFields"; import ContentCopyIcon from "@mui/icons-material/ContentCopy"; import { useNavigate } from "react-router-dom"; import { AlertColor } from "@mui/material/Alert/Alert"; +import { CreatedByItem } from "@/components/CreatedByItem.tsx"; const ExerciseDetails: FC = () => { const { enqueueSnackbar } = useSnackbar(); @@ -73,6 +73,8 @@ const ExerciseDetails: FC = () => { exerciseImage: formDataToSend.exerciseImage, solutionImage: formDataToSend.solutionImage, solveIdeaImage: formDataToSend.solveIdeaImage, + + contributors: formDataToSend.contributors, }, }, }); @@ -197,6 +199,7 @@ const ExerciseDetailsForm: FC<{ updateSignal: boolean }> = ({ exerciseImage: data.exercise.exerciseImage?.id, solutionImage: data.exercise.solutionImage?.id, solveIdeaImage: data.exercise.solveIdeaImage?.id, + contributors: data.exercise.contributors.map((c) => c.id), source: data.exercise.source, tags: data.exercise.tags.map((tag) => tag.id), }); @@ -287,18 +290,14 @@ const ExerciseDetailsForm: FC<{ updateSignal: boolean }> = ({ component="span" sx={{ color: "text.primary" }} > - Beküldő:{" "} - - - - {exercise.createdBy.name} + {exercise.contributors.length > 0 + ? "Beküldők: " + : "Beküldő:"} + + {exercise.contributors.map((user) => ( + + ))} { exerciseImage: formDataToSend.exerciseImage, solutionImage: formDataToSend.solutionImage, solveIdeaImage: formDataToSend.solveIdeaImage, + + contributors: formDataToSend.contributors, }, }, }); diff --git a/src/pages/createExercise/ExerciseFields.tsx b/src/pages/createExercise/ExerciseFields.tsx index c433ebc..119c277 100644 --- a/src/pages/createExercise/ExerciseFields.tsx +++ b/src/pages/createExercise/ExerciseFields.tsx @@ -21,6 +21,7 @@ import { useDebounce } from "react-use"; import { KaTeX } from "../../components/Katex.tsx"; import { MultiSelect } from "../../components/MultiSelect.tsx"; import { SolutionOptions } from "@/components/SolutionOptions/SolutionOptions.tsx"; +import { ContributorsSelector } from "@/components/ContributorsSelector.tsx"; const ExerciseFields: FC = () => { const { values, handleChange, handleBlur, setFieldValue } = @@ -303,12 +304,25 @@ const ExerciseFields: FC = () => { {categoryDifficultySelect} - { - setFieldValue("helpingQuestions", value); - }} - /> + + { + setFieldValue("helpingQuestions", value); + }} + /> + + { + setFieldValue( + "contributors", + user.map((u) => u.id), + ); + }} + selectedUsers={values.contributors} + /> + + ); }; diff --git a/src/util/const.ts b/src/util/const.ts index f522d50..6e7414f 100644 --- a/src/util/const.ts +++ b/src/util/const.ts @@ -108,6 +108,7 @@ export const createExerciseInitialValue: ExerciseFieldsType = { ageGroup: "JEGESMEDVE", }, ], + contributors: [], helpingQuestions: [], solution: "", solutionOptions: [], diff --git a/src/util/types.ts b/src/util/types.ts index 6f03fd5..11aadf0 100644 --- a/src/util/types.ts +++ b/src/util/types.ts @@ -68,6 +68,7 @@ export type ExerciseFieldsType = { source?: InputMaybe; status?: ExerciseStatus; tags: Array>; + contributors: Array; exerciseImageUrl?: string | null | undefined; solutionImageUrl?: string | null | undefined;