diff --git a/src/app/quiz/Search.js b/src/app/quiz/Search.js deleted file mode 100644 index 4467bd6c..00000000 --- a/src/app/quiz/Search.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright 2024 OpenBuild - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use client'; - -import { usePathname, useRouter, useSearchParams } from 'next/navigation'; -import { useDebouncedCallback } from 'use-debounce'; - -import { SearchIcon } from '@/components/Icons'; -import Input from '@/components/Input'; - -export function QuizSearch() { - const searchParams = useSearchParams(); - const { replace } = useRouter(); - const pathname = usePathname(); - - const handleSearch = useDebouncedCallback(term => { - const params = new URLSearchParams(searchParams); - params.set('page', '1'); - if (term) { - params.set('query', term); - } else { - params.delete('query'); - } - replace(`${pathname}?${params.toString()}`); - }, 300); - - return ( -
- } - onChange={e => handleSearch(e.target.value)} - className="h-10 [&>div]:pb-0" - /> -
- - ); -} diff --git a/src/app/quiz/[id]/RankListModal.js b/src/app/quiz/[id]/RankListModal.js index a06647d3..b2ddca00 100644 --- a/src/app/quiz/[id]/RankListModal.js +++ b/src/app/quiz/[id]/RankListModal.js @@ -22,8 +22,7 @@ import { Modal } from '@/components/Modal'; import useMounted from '@/hooks/useMounted'; import { fetchRankList } from '#/domain/quiz/repository'; - -import RankList from './RankList'; +import RankListView from '#/domain/quiz/views/rank-list-view'; export function RankListModal({ quizId, shown, onClose, rank }) { const [data, setData] = useState(null); @@ -48,7 +47,7 @@ export function RankListModal({ quizId, shown, onClose, rank }) { />
{loading && } - +
); diff --git a/src/app/quiz/[id]/Record.js b/src/app/quiz/[id]/Record.js index 52c7a02c..38385a66 100644 --- a/src/app/quiz/[id]/Record.js +++ b/src/app/quiz/[id]/Record.js @@ -14,17 +14,15 @@ * limitations under the License. */ -import Image from 'next/image'; -import Link from 'next/link'; import useSWR from 'swr'; import { ModalCloseIcon } from '@/components/Icons'; import { Modal } from '@/components/Modal'; // import clsx from 'clsx' import { NoData } from '@/components/NoData'; -import { formatTime, fromUtcOffset, formatTimeMeridiem } from '@/utils/date'; import { fetcher } from '@/utils/request'; +import RecordListView from '#/domain/quiz/views/record-list-view'; import { useMediaUrl } from '#/state/application/hooks'; export function Record({quizId, shown, onClose}) { @@ -39,54 +37,7 @@ export function Record({quizId, shown, onClose}) {

Challenge Record

-
- -
- {data?.map((i, k) => ( -
-
    -
  • - {i.quiz_info.title} -
    - {mediaUrl && {'user_avatar'}} -

    by {i.quiz_user?.user_nick_name}

    -
    -
  • -
  • -
    -

    Time

    -

    {formatTime(i.created_at * 1000, 'YYYY-MM-DD hh:mm:ss')}  - {formatTimeMeridiem(i.created_at * 1000)} - - (UTC+{fromUtcOffset()}) - - -

    -
    -
    -

    Score

    -

    {i.score}

    -
    -
  • -
  • - {i.score} -
  • -
-
-
- ))} -
-
+ {(!data|| data?.length === 0) &&
} diff --git a/src/app/quiz/[id]/page.js b/src/app/quiz/[id]/page.js index 94c7b8e5..0aad31f9 100644 --- a/src/app/quiz/[id]/page.js +++ b/src/app/quiz/[id]/page.js @@ -30,10 +30,10 @@ import { OViewer } from '@/components/MarkDown'; import { fetcher } from '@/utils/request'; import { CourseListViewWidget } from '#/domain/course'; +import RankListView from '#/domain/quiz/views/rank-list-view'; import QuizLimiterWidget from '#/domain/quiz/widgets/quiz-limiter'; import { useMediaUrl } from '#/state/application/hooks'; -import RankList from './RankList'; import { RankListModal } from './RankListModal'; import { Record } from './Record'; @@ -94,7 +94,7 @@ export default function Quiz({params}) { className="mt-4 md:mt-6 mb-9 md:mb-10 !font-bold px-[64px] !text-base max-md:w-full"> Challenge now - +

{setOpenRankList(true);}}>{data?.user_num} builders have participated

{ diff --git a/src/app/quiz/[id]/questions/[version]/page.js b/src/app/quiz/[id]/questions/[version]/page.js index 0e6ff132..15d33976 100644 --- a/src/app/quiz/[id]/questions/[version]/page.js +++ b/src/app/quiz/[id]/questions/[version]/page.js @@ -18,7 +18,7 @@ import QuizQuestionListView from '#/domain/quiz/views/quiz-question-list'; -export default function QuizDetails({ params }) { +export default function QuizVersion({ params }) { return ( ); diff --git a/src/app/quiz/[id]/questions/page.js b/src/app/quiz/[id]/questions/page.js index 1e2b901b..087cc02f 100644 --- a/src/app/quiz/[id]/questions/page.js +++ b/src/app/quiz/[id]/questions/page.js @@ -18,7 +18,7 @@ import QuizQuestionListView from '#/domain/quiz/views/quiz-question-list'; -export default function QuizDetails({ params }) { +export default function QuizQuestions({ params }) { return ( ); diff --git a/src/app/quiz/page.js b/src/app/quiz/page.js index 3d4d3827..c6a90260 100644 --- a/src/app/quiz/page.js +++ b/src/app/quiz/page.js @@ -22,13 +22,13 @@ import QuizBannerPic from 'public/images/quiz-banner.svg'; import QuizS1 from 'public/images/quiz-s-1.svg'; import QuizS2 from 'public/images/quiz-s-2.svg'; import QuizS3 from 'public/images/quiz-s-3.svg'; -import { useEffect,useState } from 'react'; +import { useState } from 'react'; import { ArrowRightIcon } from '@/components/Icons'; +import QuizListView from '#/domain/quiz/views/quiz-list-view'; import StartOnOpenBuild from '#/entry/components/StartOnOpenBuild'; - -import { QuizList } from './List'; +import useMounted from '#/shared/hooks/useMounted'; const Steps = [ { @@ -48,24 +48,32 @@ const Steps = [ export default function Quiz() { const [activeStep, setActiveStep] = useState(0); - useEffect(() => { + useMounted(() => { Aos.init({ delay: 100, // values from 0 to 3000, with step 50ms duration: 800, // values from 0 to 3000, with step 50ms }); - }, []); + }); return (
-

Learn & Earn

-

Discover cutting-edge protocols and ecosystems, earn prizes and thrive in the crypto space!

+

+ Learn & Earn +

+

+ Discover cutting-edge protocols and ecosystems, earn prizes and thrive{' '} + in the crypto space! +

-
+
{Steps.map((i, k) => (
@@ -87,15 +95,15 @@ export default function Quiz() { return (
{ - if(k > 0){ - setActiveStep(k-1); + if (k > 0) { + setActiveStep(k - 1); } }} />
- +

Step {k + 1}

{i.name}

@@ -103,9 +111,9 @@ export default function Quiz() {
{ - if(isNotLast){ - setActiveStep(k+1); + onClick={() => { + if (isNotLast) { + setActiveStep(k + 1); } }} /> @@ -114,17 +122,19 @@ export default function Quiz() { })}
- +

Quiz FAQ

- Who is able to participate in Quiz? + Who is able to participate in Quiz?
-

Anyone can participate in Quiz, and to claim the prize, users must connect their Github account first.

+

+ Anyone can participate in Quiz, and to claim the prize, users must connect their Github account first. +

@@ -154,10 +164,12 @@ export default function Quiz() { Can I take the Quiz if it has ended?
-

You can always take the Quiz whenever you want. However, the prize is available only when the quiz status is Ongoing.

+

+ You can always take the Quiz whenever you want. However, the prize is available only when the quiz + status is Ongoing.{' '} +

-
diff --git a/src/domain/quiz/widgets/quiz-item/QuizItem.js b/src/domain/quiz/views/quiz-list-view/QuizItem.js similarity index 96% rename from src/domain/quiz/widgets/quiz-item/QuizItem.js rename to src/domain/quiz/views/quiz-list-view/QuizItem.js index 0d24eb41..e22ef384 100644 --- a/src/domain/quiz/widgets/quiz-item/QuizItem.js +++ b/src/domain/quiz/views/quiz-list-view/QuizItem.js @@ -41,10 +41,10 @@ function QuizItem({ data, children }) {
{data?.user_list?.slice(0, 10).map(i => ( diff --git a/src/app/quiz/List.js b/src/domain/quiz/views/quiz-list-view/QuizListView.js similarity index 58% rename from src/app/quiz/List.js rename to src/domain/quiz/views/quiz-list-view/QuizListView.js index e8b8aa0c..e5a7f79d 100644 --- a/src/app/quiz/List.js +++ b/src/domain/quiz/views/quiz-list-view/QuizListView.js @@ -14,12 +14,7 @@ * limitations under the License. */ -'use client'; - -import Image from 'next/image'; -import Link from 'next/link'; import { useSearchParams, useRouter } from 'next/navigation'; -import TrophiesSvg from 'public/images/trophies.svg'; import { useState } from 'react'; import useSWR from 'swr'; import { useDebouncedCallback } from 'use-debounce'; @@ -29,62 +24,14 @@ import Input from '@/components/Input'; import { OPagination } from '@/components/Pagination'; import { ReactSelect } from '@/components/Select/ReactSelect'; import useMounted from '@/hooks/useMounted'; -import { markdownToPlainText } from '@/utils/markdown'; import { fetcher } from '@/utils/request'; -import { fetchTeamList } from '#/domain/quiz/repository'; -import { useMediaUrl } from '#/state/application/hooks'; - -function List({ data }) { - const mediaUrl = useMediaUrl(); - - return ( - -
- - -
-
-
-

{data?.title}

-

{markdownToPlainText(data?.describe)}

- {data?.reward_text &&
-
- Trophies -
-

{data?.reward_text}

-
} -
- -
-
-

- - by  - - {data?.quiz_user.user_nick_name} - - -

- | -

{data?.user_num} builders

-
- - - - - - -
- -
- - ); -} +import { fetchTeamList } from '../../repository'; +import QuizItem from './QuizItem'; const pageSize = 10; -export function QuizList() { +export default function QuizListView() { const searchParams = useSearchParams(); const router = useRouter(); const [query, setQuery] = useState(searchParams?.get('search') || ''); @@ -93,7 +40,10 @@ export function QuizList() { const [pageOffset, setPageOffset] = useState(0); const [selectedTeam, setSelectedTeam] = useState(null); const [teamOptions, setTeamOptions] = useState([]); - const { data, isLoading } = useSWR(`ts/v1/quiz?skip=${pageOffset}&take=${pageSize}&search=${query}&team_uid=${teamUid}`, fetcher); + const { data, isLoading } = useSWR( + `ts/v1/quiz?skip=${pageOffset}&take=${pageSize}&search=${query}&team_uid=${teamUid}`, + fetcher, + ); const updateUrlParams = (search, teamUid) => { const params = new URLSearchParams(); @@ -173,7 +123,7 @@ export function QuizList() { ) : ( <> {data?.list.map((i, k) => ( - + ))} diff --git a/src/domain/quiz/widgets/quiz-item/index.js b/src/domain/quiz/views/quiz-list-view/index.js similarity index 93% rename from src/domain/quiz/widgets/quiz-item/index.js rename to src/domain/quiz/views/quiz-list-view/index.js index bcd26808..1fcc1e37 100644 --- a/src/domain/quiz/widgets/quiz-item/index.js +++ b/src/domain/quiz/views/quiz-list-view/index.js @@ -14,4 +14,4 @@ * limitations under the License. */ -export { default } from './QuizItem'; +export { default } from './QuizListView'; diff --git a/src/domain/quiz/widgets/quiz-item/style.module.scss b/src/domain/quiz/views/quiz-list-view/style.module.scss similarity index 100% rename from src/domain/quiz/widgets/quiz-item/style.module.scss rename to src/domain/quiz/views/quiz-list-view/style.module.scss diff --git a/src/app/quiz/[id]/RankList.js b/src/domain/quiz/views/rank-list-view/RankListView.js similarity index 97% rename from src/app/quiz/[id]/RankList.js rename to src/domain/quiz/views/rank-list-view/RankListView.js index 1861a123..072747b2 100644 --- a/src/app/quiz/[id]/RankList.js +++ b/src/domain/quiz/views/rank-list-view/RankListView.js @@ -14,8 +14,6 @@ * limitations under the License. */ -'use client'; - import Image from 'next/image'; import Rank1Icon from 'public/images/svg/rank-1.svg'; import Rank2Icon from 'public/images/svg/rank-2.svg'; @@ -23,7 +21,7 @@ import Rank3Icon from 'public/images/svg/rank-3.svg'; import { useMediaUrl } from '#/state/application/hooks'; -export default function RankList({ rank, list }) { +export default function RankListView({ rank, list }) { const mediaUrl = useMediaUrl(); return ( diff --git a/src/domain/quiz/views/rank-list-view/index.js b/src/domain/quiz/views/rank-list-view/index.js new file mode 100644 index 00000000..1b3d5f97 --- /dev/null +++ b/src/domain/quiz/views/rank-list-view/index.js @@ -0,0 +1,17 @@ +/** + * Copyright 2024 OpenBuild + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { default } from './RankListView'; diff --git a/src/domain/quiz/views/record-list-view/RecordListView.js b/src/domain/quiz/views/record-list-view/RecordListView.js new file mode 100644 index 00000000..71a2eb3a --- /dev/null +++ b/src/domain/quiz/views/record-list-view/RecordListView.js @@ -0,0 +1,78 @@ +/** + * Copyright 2024 OpenBuild + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Image from 'next/image'; +import Link from 'next/link'; + +import { formatTime, fromUtcOffset, formatTimeMeridiem } from '@/utils/date'; + +function RecordListView({ + data = [], + mediaUrl, +}) { + return ( +
+
    +
  • Quiz
  • +
  • Time
  • +
  • Score
  • +
+
+ {data?.map((i, k) => ( +
+
    +
  • + {i.quiz_info.title} +
    + {mediaUrl && {'user_avatar'}} +

    by {i.quiz_user?.user_nick_name}

    +
    +
  • +
  • +
    +

    Time

    +

    {formatTime(i.created_at * 1000, 'YYYY-MM-DD hh:mm:ss')}  + {formatTimeMeridiem(i.created_at * 1000)} + + (UTC+{fromUtcOffset()}) + + +

    +
    +
    +

    Score

    +

    {i.score}

    +
    +
  • +
  • + {i.score} +
  • +
+
+
+ ))} +
+
+ ); +} + +export default RecordListView; diff --git a/src/domain/quiz/views/record-list-view/index.js b/src/domain/quiz/views/record-list-view/index.js new file mode 100644 index 00000000..ccda1a42 --- /dev/null +++ b/src/domain/quiz/views/record-list-view/index.js @@ -0,0 +1,17 @@ +/** + * Copyright 2024 OpenBuild + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { default } from './RecordListView'; diff --git a/src/domain/quiz/widgets/quiz-list-item/QuizListItem.js b/src/domain/quiz/widgets/quiz-list-item/QuizListItem.js new file mode 100644 index 00000000..cc9be2ff --- /dev/null +++ b/src/domain/quiz/widgets/quiz-list-item/QuizListItem.js @@ -0,0 +1,84 @@ +/** + * Copyright 2024 OpenBuild + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Image from 'next/image'; +import Link from 'next/link'; +import TrophiesSvg from 'public/images/trophies.svg'; + +import { markdownToPlainText } from '#/shared/utils/markdown'; +import { useMediaUrl } from '#/state/application/hooks'; +export default function QuizListItem({ data }) { + const mediaUrl = useMediaUrl(); + + return ( + +
+ +
+
+
+

{data?.title}

+

{markdownToPlainText(data?.describe)}

+ {data?.reward_text && ( +
+
+ Trophies +
+

{data?.reward_text}

+
+ )} +
+ +
+
+

+ + by  + + {data?.quiz_user.user_nick_name} + +

+ | +

+ {data?.user_num} builders +

+
+ + + + + + +
+
+ + ); +} diff --git a/src/domain/quiz/widgets/quiz-list-item/index.js b/src/domain/quiz/widgets/quiz-list-item/index.js new file mode 100644 index 00000000..29e40f98 --- /dev/null +++ b/src/domain/quiz/widgets/quiz-list-item/index.js @@ -0,0 +1,17 @@ +/** + * Copyright 2024 OpenBuild + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { default } from './QuizListItem';