diff --git a/.graphqlrc.yml b/.graphqlrc.yml index 438e87b..09c907b 100644 --- a/.graphqlrc.yml +++ b/.graphqlrc.yml @@ -1,2 +1,2 @@ -schema: './apps/api/schema.gql' -documents: './apps/web/**/*.gql' +schema: './apps/api/schema.graphql' +documents: './apps/web/**/*.graphql' diff --git a/apps/api/index.ts b/apps/api/index.ts index 1f72b45..257f27d 100644 --- a/apps/api/index.ts +++ b/apps/api/index.ts @@ -7,7 +7,7 @@ import { schemaAsString } from './src/graphql'; const main = async () => { try { - await writeFile('./schema.gql', schemaAsString); + await writeFile('./schema.graphql', schemaAsString); server.listen({ port: env.PORT }); logger.success(`🚀 Server ready at http://localhost:${env.PORT}`); diff --git a/apps/api/schema.gql b/apps/api/schema.graphql similarity index 53% rename from apps/api/schema.gql rename to apps/api/schema.graphql index 07fc514..6b79335 100644 --- a/apps/api/schema.gql +++ b/apps/api/schema.graphql @@ -1,6 +1,8 @@ -"""Auth0 user info""" +""" +Auth0 user info +""" type AuthInfo { - sub: String + sub: String } """ @@ -9,8 +11,8 @@ A date string, such as 2007-12-03, compliant with the `full-date` format outline scalar Date input DateRangeInput { - gte: Date - lte: Date + gte: Date + lte: Date } """ @@ -19,55 +21,57 @@ A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `dat scalar DateTime input NumberRangeInput { - gte: Int - lte: Int + gte: Int + lte: Int } input PaginationInput { - page: Int = 1 - perPage: Int = 10 + page: Int = 1 + perPage: Int = 10 } type Query { - """Auth0 context info""" - authInfo: AuthInfo - tasks(filter: TaskFilterInput, pagination: PaginationInput): [Task!]! + """ + Auth0 context info + """ + authInfo: AuthInfo + tasks(filter: TaskFilterInput, pagination: PaginationInput): [Task!]! } scalar SearchString type Task { - author: User! - description: String! - difficulty: String! - id: ID! - rating: Int! - status: String! - thumbnailUrl: String! - title: String! + author: User! + description: String! + difficulty: String! + id: ID! + rating: Int! + status: String! + thumbnailUrl: String! + title: String! } enum TaskDifficulty { - ADVANCED - BEGINNER - INTERMEDIATE + ADVANCED + BEGINNER + INTERMEDIATE } input TaskFilterInput { - created_at: DateRangeInput - description: SearchString - difficulty: TaskDifficulty - status: TaskStatus = ACTIVE - title: SearchString - updated_at: DateRangeInput + created_at: DateRangeInput + description: SearchString + difficulty: TaskDifficulty + status: TaskStatus = ACTIVE + title: SearchString + updated_at: DateRangeInput } enum TaskStatus { - ACTIVE - IN_REVIEW - REJECTED + ACTIVE + IN_REVIEW + REJECTED } type User { - id: ID! -} \ No newline at end of file + id: ID! +} diff --git a/apps/web/components/molecules/challengeItem/challengeItem.tsx b/apps/web/components/molecules/challengeItem/challengeItem.tsx index 95309ad..3d86b20 100644 --- a/apps/web/components/molecules/challengeItem/challengeItem.tsx +++ b/apps/web/components/molecules/challengeItem/challengeItem.tsx @@ -1,18 +1,28 @@ -import { Card, Heading, Text, CategoryTag } from 'ui'; +import { Card, Heading, Text } from 'ui'; import { ChartBarIcon } from '@heroicons/react/20/solid'; import Image from 'next/image'; -import type { Challenge } from '../../../types/types'; import clsx from 'clsx'; +import type { Task } from 'generated'; -type TaskItemProps = Challenge; +type TaskItemProps = Task; +const translateToPolish = (difficulty: string) => { + switch (difficulty) { + case 'ADVANCED': + return 'Zaawansowany'; + case 'BEGINNER': + return 'Początkujący'; + case 'INTERMEDIATE': + return 'Mid'; + } +}; export const ChallengeItem = ({ id, title, - image, + thumbnailUrl: image, description, difficulty, - tags, + // tags, rating, }: TaskItemProps) => { return ( @@ -23,9 +33,9 @@ export const ChallengeItem = ({
@@ -39,7 +49,7 @@ export const ChallengeItem = ({
- {difficulty} + {translateToPolish(difficulty)}
{Array.from({ length: 5 }, (_, i) => { @@ -54,7 +64,6 @@ export const ChallengeItem = ({ xmlns="http://www.w3.org/2000/svg" key={i} > - {/*First star*/} ); @@ -66,9 +75,9 @@ export const ChallengeItem = ({
    - {tags.map((tag) => { - return ; - })} + {/*{tags.map((tag) => {*/} + {/* return ;*/} + {/*})}*/}
diff --git a/apps/web/components/molecules/filters/filters.tsx b/apps/web/components/molecules/filters/filters.tsx index 22b5448..41c1d6b 100644 --- a/apps/web/components/molecules/filters/filters.tsx +++ b/apps/web/components/molecules/filters/filters.tsx @@ -1,5 +1,5 @@ import { Disclosure } from '@headlessui/react'; -import { Text, Checkbox, Heading } from 'ui'; +import { Checkbox, Heading, Text } from 'ui'; import { MinusIcon, PlusIcon } from '@heroicons/react/20/solid'; import type { Filter } from '../../../types/types'; @@ -35,7 +35,7 @@ export const Filters = ({ filters }: FiltersProps) => {
{section.options.map((option) => (
- +
))}
diff --git a/apps/web/components/organisms/challengesList/challengesList.tsx b/apps/web/components/organisms/challengesList/challengesList.tsx index 6862597..ffdc16f 100644 --- a/apps/web/components/organisms/challengesList/challengesList.tsx +++ b/apps/web/components/organisms/challengesList/challengesList.tsx @@ -1,9 +1,10 @@ import { ChallengeItem } from 'molecules/challengeItem/challengeItem'; -import type { Challenge } from '../../../types/types'; +import type { GetTaskWithPaginationQueryHookResult } from 'generated'; type TasksListProps = { - challenges: Challenge[]; + challenges: GetTaskWithPaginationQueryHookResult['data']['tasks'][]; }; + export const ChallengesList = ({ challenges }: TasksListProps) => { return (
@@ -12,10 +13,6 @@ export const ChallengesList = ({ challenges }: TasksListProps) => { return ; })} - - {/*
*/} - {/* Zadania*/} - {/*
*/}
); }; diff --git a/apps/web/components/templates/challenges/all/allChallenges.tsx b/apps/web/components/templates/challenges/all/allChallenges.tsx index a38bdf8..51e4a00 100644 --- a/apps/web/components/templates/challenges/all/allChallenges.tsx +++ b/apps/web/components/templates/challenges/all/allChallenges.tsx @@ -1,13 +1,13 @@ -import { Heading, VisuallyHidden } from 'ui'; +import { Heading, Spinner, VisuallyHidden } from 'ui'; import { ChallengesList } from 'organisms/challengesList/challengesList'; -import { Fragment } from 'react'; +import { Fragment, useState } from 'react'; import { Dialog, Transition } from '@headlessui/react'; -import type { Challenge, Filter, SortOption } from '../../../../types/types'; -import { useState } from 'react'; +import type { Filter, SortOption } from '../../../../types/types'; import { XMarkIcon } from '@heroicons/react/24/outline'; import { FunnelIcon } from '@heroicons/react/20/solid'; import { Filters } from 'molecules/filters/filters'; import { SortMenu } from 'organisms/sortMenu/sortMenu'; +import { useGetTaskWithPaginationQuery } from 'generated'; const sortOptions: SortOption[] = [ { name: 'Difficulty', value: 'difficulty', href: '#', current: true }, @@ -17,45 +17,26 @@ const sortOptions: SortOption[] = [ const filters: Filter[] = [ { id: 'difficulty', - name: 'Difficulty', + name: 'Poziom trudności', options: [ - { value: 'easy', label: 'Easy', checked: false }, - { value: 'medium', label: 'Medium', checked: true }, - { value: 'hard', label: 'Hard', checked: false }, + { value: 'INTERMEDIATE', label: 'Mid', checked: false }, + { value: 'BEGINNER', label: 'Początkujący', checked: false }, + { value: 'ADVANCED', label: 'Zaawansowany', checked: false }, ], }, { id: 'category', name: 'Category', options: [] }, ]; -export const challenges: Challenge[] = [ - { - id: '1', - title: 'First Challenge', - description: - 'This is example of challenge. In hac habitasse platea dictumst. Praesent eu auctor velit. Cras mattis gravida odio euismod placerat. Morbi vestibulum dapibus diam, a lacinia felis porttitor vel. Ut sodales tincidunt orci, vel condimentum nibh. Fusce in elit euismod, laoreet felis vel, rutrum lacus.', - designs: '', - difficulty: 'medium', - image: - 'https://images.unsplash.com/photo-1498008122250-bcb854c8462d?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80', - rating: 5, - tags: ['TypeScript'], - }, - { - id: '2', - title: 'Second Challenge', - description: - 'This is example of challenge. In hac habitasse platea dictumst. Praesent eu auctor velit. Cras mattis gravida odio euismod placerat. Morbi vestibulum dapibus diam, a lacinia felis porttitor vel. Ut sodales tincidunt orci, vel condimentum nibh. Fusce in elit euismod, laoreet felis vel, rutrum lacus.', - - designs: '', - difficulty: 'advanced', - image: - 'https://cdn.pixabay.com/photo/2020/11/28/06/15/cold-5783718_1280.jpg', - rating: 3.26, - tags: ['JavaScript', 'React'], - }, -]; export const AllChallengesPage = () => { const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [page, setPage] = useState(1); + + const { data, loading } = useGetTaskWithPaginationQuery({ + variables: { page }, + }); + + const challenges = data?.tasks || []; return ( <> @@ -100,7 +81,6 @@ export const AllChallengesPage = () => {
- {/* Filters */}
Filtry @@ -136,12 +116,11 @@ export const AllChallengesPage = () => { Zadania
- {/* Filters */} Filters - + {loading ? : }
diff --git a/apps/web/components/templates/challenges/all/getAllTasks.graphql b/apps/web/components/templates/challenges/all/getAllTasks.graphql new file mode 100644 index 0000000..44caf64 --- /dev/null +++ b/apps/web/components/templates/challenges/all/getAllTasks.graphql @@ -0,0 +1,21 @@ +query GetAllActiveTasks { + tasks(filter: { status: ACTIVE }) { + id + title + description + difficulty + thumbnailUrl + rating + } +} + +query GetTaskWithPagination($page: Int) { + tasks(filter: { status: ACTIVE }, pagination: { page: $page, perPage: 3 }) { + id + title + description + difficulty + thumbnailUrl + rating + } +} diff --git a/apps/web/next.config.js b/apps/web/next.config.js index 1abd819..2d63c7c 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -3,6 +3,7 @@ const nextConfig = { images: { domains: [ 'avatars.githubusercontent.com', + 'loremflickr.com', 'images.unsplash.com', 'cdn.pixabay.com', ], diff --git a/packages/generated/codegen.ts b/packages/generated/codegen.ts index 1872eef..10c647b 100644 --- a/packages/generated/codegen.ts +++ b/packages/generated/codegen.ts @@ -1,24 +1,29 @@ import type { CodegenConfig } from '@graphql-codegen/cli'; - + const config: CodegenConfig = { - schema: '../../apps/api/schema.gql', - documents: ['../../apps/web/**/*.gql'], + schema: '../../apps/api/schema.graphql', + documents: ['../../apps/web/**/*.graphql'], generates: { './generated.ts': { - plugins: ['typescript', 'typescript-operations', 'typescript-react-apollo', 'typescript-resolvers'], + plugins: [ + 'typescript', + 'typescript-operations', + 'typescript-react-apollo', + 'typescript-resolvers', + ], config: { withHooks: true, scalars: { - 'Date': 'string', - 'DateTime': 'string', - 'SearchString': 'string' - } + Date: 'string', + DateTime: 'string', + SearchString: 'string', + }, }, hooks: { - 'afterOneFileWrite': ['yarn postgenerate'] - } - } - } + afterOneFileWrite: ['yarn postgenerate'], + }, + }, + }, }; - -export default config; \ No newline at end of file + +export default config; diff --git a/packages/generated/generated.ts b/packages/generated/generated.ts index 66ca095..8d0852d 100644 --- a/packages/generated/generated.ts +++ b/packages/generated/generated.ts @@ -93,46 +93,98 @@ export type User = { id: Scalars['ID']; }; -export type GetTasksQueryVariables = Exact<{ [key: string]: never; }>; +export type GetAllActiveTasksQueryVariables = Exact<{ [key: string]: never; }>; -export type GetTasksQuery = { __typename?: 'Query', tasks: Array<{ __typename?: 'Task', id: string }> }; +export type GetAllActiveTasksQuery = { __typename?: 'Query', tasks: Array<{ __typename?: 'Task', id: string, title: string, description: string, difficulty: string, thumbnailUrl: string, rating: number }> }; +export type GetTaskWithPaginationQueryVariables = Exact<{ + page?: InputMaybe; +}>; + + +export type GetTaskWithPaginationQuery = { __typename?: 'Query', tasks: Array<{ __typename?: 'Task', id: string, title: string, description: string, difficulty: string, thumbnailUrl: string, rating: number }> }; + + +export const GetAllActiveTasksDocument = gql` + query GetAllActiveTasks { + tasks(filter: {status: ACTIVE}) { + id + title + description + difficulty + thumbnailUrl + rating + } +} + `; -export const GetTasksDocument = gql` - query GetTasks { - tasks { +/** + * __useGetAllActiveTasksQuery__ + * + * To run a query within a React component, call `useGetAllActiveTasksQuery` and pass it any options that fit your needs. + * When your component renders, `useGetAllActiveTasksQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetAllActiveTasksQuery({ + * variables: { + * }, + * }); + */ +export function useGetAllActiveTasksQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetAllActiveTasksDocument, options); + } +export function useGetAllActiveTasksLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetAllActiveTasksDocument, options); + } +export type GetAllActiveTasksQueryHookResult = ReturnType; +export type GetAllActiveTasksLazyQueryHookResult = ReturnType; +export type GetAllActiveTasksQueryResult = Apollo.QueryResult; +export const GetTaskWithPaginationDocument = gql` + query GetTaskWithPagination($page: Int) { + tasks(filter: {status: ACTIVE}, pagination: {page: $page, perPage: 3}) { id + title + description + difficulty + thumbnailUrl + rating } } `; /** - * __useGetTasksQuery__ + * __useGetTaskWithPaginationQuery__ * - * To run a query within a React component, call `useGetTasksQuery` and pass it any options that fit your needs. - * When your component renders, `useGetTasksQuery` returns an object from Apollo Client that contains loading, error, and data properties + * To run a query within a React component, call `useGetTaskWithPaginationQuery` and pass it any options that fit your needs. + * When your component renders, `useGetTaskWithPaginationQuery` returns an object from Apollo Client that contains loading, error, and data properties * you can use to render your UI. * * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; * * @example - * const { data, loading, error } = useGetTasksQuery({ + * const { data, loading, error } = useGetTaskWithPaginationQuery({ * variables: { + * page: // value for 'page' * }, * }); */ -export function useGetTasksQuery(baseOptions?: Apollo.QueryHookOptions) { +export function useGetTaskWithPaginationQuery(baseOptions?: Apollo.QueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(GetTasksDocument, options); + return Apollo.useQuery(GetTaskWithPaginationDocument, options); } -export function useGetTasksLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { +export function useGetTaskWithPaginationLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(GetTasksDocument, options); + return Apollo.useLazyQuery(GetTaskWithPaginationDocument, options); } -export type GetTasksQueryHookResult = ReturnType; -export type GetTasksLazyQueryHookResult = ReturnType; -export type GetTasksQueryResult = Apollo.QueryResult; +export type GetTaskWithPaginationQueryHookResult = ReturnType; +export type GetTaskWithPaginationLazyQueryHookResult = ReturnType; +export type GetTaskWithPaginationQueryResult = Apollo.QueryResult; export type ResolverTypeWrapper = Promise | T; diff --git a/packages/ui/components/molecules/checkbox/checkbox.tsx b/packages/ui/components/molecules/checkbox/checkbox.tsx index 8d1284c..77dc690 100644 --- a/packages/ui/components/molecules/checkbox/checkbox.tsx +++ b/packages/ui/components/molecules/checkbox/checkbox.tsx @@ -2,9 +2,10 @@ import { useId } from 'react'; type CheckboxProps = { label: string; + checked: boolean; }; -export const Checkbox = ({ label }: CheckboxProps) => { +export const Checkbox = ({ label, checked }: CheckboxProps) => { const id = useId(); return (
@@ -12,6 +13,7 @@ export const Checkbox = ({ label }: CheckboxProps) => { id={id} name={id} type="checkbox" + checked={checked} className="h-4 w-4 rounded-lg border-gray-200 text-indigo-600 dark:border-gray-300 focus:ring-indigo-500" />