Skip to content

Commit e7d1080

Browse files
committed
Merge branch 'stage'
2 parents 4b06856 + e6020cf commit e7d1080

File tree

14 files changed

+197
-67
lines changed

14 files changed

+197
-67
lines changed

src/components/cards/Reputation.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,16 @@ interface ReputationCardProps {
3232
*/
3333
export default function ReputationCard({ details = {} }: ReputationCardProps): ReactElement {
3434
return (
35-
<div className="flex space-x-3 text-left hover:bg-gray-50 pb-3 -mx-5 px-5">
36-
<Avatar icon={details.community?.icon} color={details.community?.colors?.cover?.background || details.community?.colors.primary} size="medium" shape="rounded" />
35+
<div className="flex space-x-3 text-left hover:bg-gray-50 py-3 -mx-5 px-5 relative">
36+
<Avatar
37+
icon={details.community?.icon}
38+
color={details.community?.colors?.cover?.background || details.community?.colors.primary}
39+
size="medium"
40+
shape="rounded"
41+
useLink={false}
42+
/>
3743
{details?.score && (
38-
<Link href={details?.community ? `/communities/${details.community.slug}` : ""} className="pt-1">
44+
<Link href={details?.community ? `/communities/${details.community.slug}` : ""} className="pt-1 before:content-[''] before:absolute before:top-0 before:left-0 before:w-full before:h-full before:z-0 before:block">
3945
<span className="block text-base font-medium leading-normal">
4046
<Currency value={details.score} token="REP" />
4147
</span>

src/components/popups/user/Dropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ const UserProfileDropdown = ({ buttonStyles, onClose }: { buttonStyles?: CSSProp
128128
) : (
129129
<></>
130130
)}
131-
{showLanguageSwitcher && <LanguageList />}
131+
{showLanguageSwitcher && <LanguageList onSelect={onClose} />}
132132
<div className="p-4 flex justify-center bg-indigo-50">
133133
<div className="z-10">
134134
<Button

src/components/sections/bounties/Navigation.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export default function BountiesNavigation(): ReactElement {
5555
...UniqBy(
5656
bounties.map((bounty) => {
5757
return {
58-
label: bounty.name,
58+
label: bounty.community,
5959
exact: true,
6060
link: `/bounties/${bounty.slug}`,
6161
};

src/components/sections/learning-modules/InteractiveModule/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import InteractiveModuleItem from "@/components/sections/learning-modules/Intera
1010
import { authCheck } from "@/store/feature/auth.slice";
1111
import { Course, InteractiveModule as InteractiveModuleType } from "@/types/course";
1212
import { hidePageNavigation, showPageNavigation } from "@/store/feature/communities/navigation.slice";
13-
import { checkAnswer, submitModuleAnswer } from "@/store/feature/learningModules.slice";
13+
import { checkAnswer } from "@/store/feature/learningModules.slice";
14+
import { submitModuleAnswer } from "@/store/services/learningModules.service";
1415
import { IRootState } from "@/store";
1516

1617
/**

src/pages/communities/[slug]/challenges/[challenge_id]/learning-modules/[id].tsx

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import Head from "next/head";
44
import { useDispatch } from "@/hooks/useTypedDispatch";
55
import { Community } from "@/types/community";
66
import { Challenge, LearningModule } from "@/types/course";
7-
import { findLearningModule, setCurrentLearningModule } from "@/store/feature/learningModules.slice";
7+
import { setCurrentLearningModule } from "@/store/feature/learningModules.slice";
8+
import { findLearningModule } from "@/store/services/learningModules.service";
89
import { setCurrentCommunity } from "@/store/feature/community.slice";
910
import { getMetadataDescription, getMetadataTitle } from "@/utilities/Metadata";
1011
import DefaultLayout from "@/components/layout/Default";
@@ -13,7 +14,7 @@ import { initChallengeNavigationMenu } from "@/store/feature/communities/navigat
1314
import { setColors } from "@/store/feature/ui.slice";
1415
import useNavigation from "@/hooks/useNavigation";
1516
import { GetServerSideProps } from "next";
16-
import { wrapper } from "@/store";
17+
import { IRootState, wrapper } from "@/store";
1718
import { fetchCurrentCommunity } from "@/store/services/community.service";
1819
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
1920
import ChallengeOverviewCard from "@/components/cards/challenge/Overview";
@@ -22,6 +23,10 @@ import { fetchChallenge } from "@/store/services/communities/challenges";
2223
import PageNavigation from "@/components/sections/courses/PageNavigation";
2324
import ChallengeCard from "@/components/cards/challenge/Challenge";
2425
import { useTranslation } from "next-i18next";
26+
import { useMultiSelector } from "@/hooks/useTypedSelector";
27+
import Section from "@/components/ui/Section";
28+
import Loader from "@/components/ui/Loader";
29+
import { useRouter } from "next/router";
2530

2631
/**
2732
* Learning module page props interfae
@@ -38,6 +43,11 @@ interface LearningModulePageProps {
3843
};
3944
}
4045

46+
interface LearningModuleMultiselector {
47+
learningModule: LearningModule,
48+
loading: boolean
49+
}
50+
4151
/**
4252
* Learning module module view page
4353
* @date 4/24/2023 - 8:35:52 PM
@@ -47,27 +57,45 @@ interface LearningModulePageProps {
4757
* @returns
4858
*/
4959
export default function LearningModulePage(props: LearningModulePageProps) {
50-
const { community, learningModule, challenge } = props.pageProps;
60+
const { community, challenge } = props.pageProps;
61+
const { learningModule, loading } = useMultiSelector<unknown, LearningModuleMultiselector>({
62+
learningModule: (state: IRootState) => state.learningModules.current,
63+
loading: (state: IRootState) => state.learningModules.loading
64+
})
5165
const dispatch = useDispatch();
5266
const { t } = useTranslation();
5367
const navigation = useNavigation();
68+
const router = useRouter()
69+
const { query, locale } = router
5470

5571
useEffect(() => {
5672
dispatch(setCurrentCommunity(community));
5773
dispatch(setCurrentLearningModule(learningModule));
5874
dispatch(setColors(community.colors));
5975
dispatch(initChallengeNavigationMenu(navigation.community));
60-
}, [community, learningModule, navigation.community]);
76+
dispatch(findLearningModule({ id: query?.id as string, locale }))
77+
}, [community?.colors, locale]);
78+
6179

6280
const title = getMetadataTitle(learningModule?.title);
6381
const descriptions = getMetadataDescription(learningModule?.description);
6482

65-
const paths = useMemo(() => [challenge.name, learningModule?.title], [challenge.name, learningModule?.title]);
83+
const paths = useMemo(() => [challenge.name, learningModule?.title], [challenge.name, learningModule]);
6684

6785
const isLastLearningModule = useMemo(() => {
86+
if (!learningModule) return false
6887
if (!challenge.learningModules || !challenge.learningModules.length) return false;
6988
return learningModule.id === challenge.learningModules[challenge.learningModules.length - 1].id;
70-
}, [learningModule.id, challenge.learningModules]);
89+
}, [learningModule, challenge.learningModules]);
90+
91+
if (loading)
92+
93+
return (
94+
<Section className="h-[50vh] flex items-center justify-center">
95+
<Loader />
96+
</Section>
97+
);
98+
7199
return (
72100
<>
73101
<Head>
@@ -108,22 +136,19 @@ export const getServerSideProps: GetServerSideProps = wrapper.getServerSideProps
108136
try {
109137
const communitySlug = params?.slug as string;
110138
const challenge_id = params?.challenge_id as string;
111-
const learningModule_id = params?.id as string;
112139

113-
const [{ data: community }, { data: challenge }, { payload: learningModule }, translations] = await Promise.all([
140+
const [{ data: community }, { data: challenge }, translations] = await Promise.all([
114141
store.dispatch(fetchCurrentCommunity({ slug: communitySlug, locale })),
115-
store.dispatch(fetchChallenge({ id: challenge_id, relations: ["learning-modules", "rubric"] })),
116-
store.dispatch(findLearningModule(learningModule_id)),
142+
store.dispatch(fetchChallenge({ id: challenge_id, relations: ["learning-modules", "rubric"], locale })),
117143
serverSideTranslations(locale as string),
118144
]);
119145

120-
if (Object.entries(community).length === 0 || Object.entries(challenge).length === 0 || Object.entries(learningModule).length === 0)
146+
if (Object.entries(community).length === 0 || Object.entries(challenge).length === 0)
121147
throw new Error("Failed to fetch learning module");
122148

123149
return {
124150
props: {
125151
community,
126-
learningModule,
127152
challenge,
128153
...translations,
129154
},

src/pages/communities/[slug]/challenges/[challenge_id]/submissions/[submission_id].tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export default function SubmissionPage() {
3535
};
3636
setLoading(true);
3737
await Promise.all([
38-
dispatch(fetchChallenge({ id: challenge_id as string, relations: ["rubric"] })),
38+
dispatch(fetchChallenge({ id: challenge_id as string, relations: ["rubric"], locale })),
3939
dispatch(fetchCurrentCommunity(fetchCurrentCommunityPayload)),
4040
dispatch(findSubmssionById({ id: submission_id as string })),
4141
]);

src/pages/communities/[slug]/challenges/[challenge_id]/submissions/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export const getServerSideProps: GetServerSideProps = wrapper.getServerSideProps
118118
const [{ data: currentCommunity }, { data: submissions }, { data: challenge }, translations] = await Promise.all([
119119
dispatch(fetchCurrentCommunity({ slug: slug as string, locale: locale as string })),
120120
dispatch(fetchAllSubmission({ challengeId: challenge_id as string, locale: locale as string })),
121-
dispatch(fetchChallenge({ id: challenge_id as string, relations: ["rubric", "courses", "learning-modules"] })),
121+
dispatch(fetchChallenge({ id: challenge_id as string, relations: ["rubric", "courses", "learning-modules"], locale })),
122122
serverSideTranslations(locale as string),
123123
]);
124124

src/pages/communities/[slug]/courses/[course_slug]/learning-modules/[id].tsx

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import Head from "next/head";
44
import { useDispatch } from "@/hooks/useTypedDispatch";
55
import { Community } from "@/types/community";
66
import { Challenge, Course, LearningModule } from "@/types/course";
7-
import { findLearningModule } from "@/store/feature/learningModules.slice";
7+
import { findLearningModule } from "@/store/services/learningModules.service";
88
import { getMetadataDescription, getMetadataTitle } from "@/utilities/Metadata";
99
import DefaultLayout from "@/components/layout/Default";
1010
import Header from "@/components/sections/learning-modules/Header";
1111
import { initCourseNavigationMenu } from "@/store/feature/communities/navigation.slice";
12-
import { wrapper } from "@/store";
12+
import { IRootState, wrapper } from "@/store";
1313
import { fetchCurrentCommunity } from "@/store/services/community.service";
1414
import { fetchCourse } from "@/store/services/course.service";
1515
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
@@ -20,6 +20,10 @@ import ChallengeCard from "@/components/cards/challenge/Challenge";
2020
import { useTranslation } from "next-i18next";
2121
import PageNavigation from "@/components/sections/courses/PageNavigation";
2222
import { NotFoundError } from "@/utilities/errors/NotFoundError";
23+
import { useRouter } from "next/router";
24+
import { useMultiSelector } from "@/hooks/useTypedSelector";
25+
import Section from "@/components/ui/Section";
26+
import Loader from "@/components/ui/Loader";
2327

2428
/**
2529
* Learning module page props interfae
@@ -32,11 +36,15 @@ interface LearningModulePageProps {
3236
pageProps: {
3337
community: Community;
3438
course: Course;
35-
learningModule: LearningModule;
3639
challenges: Challenge[];
3740
};
3841
}
3942

43+
interface LearningModuleMultiselector {
44+
learningModule: LearningModule,
45+
loading: boolean
46+
}
47+
4048
/**
4149
* Learning module module view page
4250
* @date 4/24/2023 - 8:35:52 PM
@@ -46,23 +54,37 @@ interface LearningModulePageProps {
4654
* @returns
4755
*/
4856
export default function LearningModulePage(props: LearningModulePageProps): ReactElement {
49-
const { course, learningModule, community } = props.pageProps;
57+
const { course, community } = props.pageProps;
58+
const { learningModule, loading } = useMultiSelector<unknown, LearningModuleMultiselector>({
59+
learningModule: (state: IRootState) => state.learningModules.current,
60+
loading: (state: IRootState) => state.learningModules.loading
61+
})
5062
const dispatch = useDispatch();
5163
const navigation = useNavigation();
5264
const { t } = useTranslation();
65+
const router = useRouter()
66+
const { query, locale } = router
5367

5468
useEffect(() => {
5569
dispatch(initCourseNavigationMenu(navigation.community));
56-
}, [dispatch]);
70+
dispatch(findLearningModule({ id: query?.id as string, locale }))
71+
}, [dispatch, locale]);
5772

58-
const title = getMetadataTitle(learningModule.title!, course.name!);
59-
const descriptions = getMetadataDescription(learningModule.description!);
73+
const title = useMemo(() => getMetadataTitle(learningModule?.title, course.name!), [course.name, learningModule]);
74+
const descriptions = useMemo(() => getMetadataDescription(learningModule?.description), [learningModule]);
6075
const paths = useMemo(() => [learningModule?.title], [learningModule?.title]);
6176
const isLastLearningModule = useMemo(() => {
77+
if (!learningModule) return false
6278
if (!course.learningModules || !course.learningModules.length) return false;
6379
return learningModule.id === course.learningModules[course.learningModules.length - 1].id;
64-
}, [learningModule.id, course.learningModules]);
80+
}, [learningModule, course.learningModules]);
6581

82+
if (loading)
83+
return (
84+
<Section className="h-[50vh] flex items-center justify-center">
85+
<Loader />
86+
</Section>
87+
);
6688
return (
6789
<>
6890
<Head>
@@ -107,20 +129,17 @@ export const getServerSideProps = wrapper.getServerSideProps((store) => async ({
107129
try {
108130
const communitySlug = params?.slug as string;
109131
const courseSlug = params?.course_slug as string;
110-
const id = params?.id as string;
111132

112-
const [{ data: community }, { data: course }, { payload: learningModule }, translations] = await Promise.all([
133+
const [{ data: community }, { data: course }, translations] = await Promise.all([
113134
store.dispatch(fetchCurrentCommunity({ slug: communitySlug, locale })),
114135
store.dispatch(fetchCourse({ slug: courseSlug, locale })),
115-
store.dispatch(findLearningModule(id)),
116136
serverSideTranslations(locale as string),
117137
]);
118-
if (!community || !course || !learningModule) throw new NotFoundError();
138+
if (!community || !course) throw new NotFoundError();
119139
return {
120140
props: {
121141
community,
122142
course,
123-
learningModule,
124143
...translations,
125144
},
126145
};

src/pages/communities/[slug]/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const getServerSideProps = wrapper.getServerSideProps((store) => async ({
4747

4848
const [{ data: community }, { data: challenges }, { data: scoreboard }, translations] = await Promise.all([
4949
store.dispatch(fetchCurrentCommunity({ slug, locale })),
50-
store.dispatch(fetchAllChallenges({ slug })),
50+
store.dispatch(fetchAllChallenges({ slug, locale })),
5151
store.dispatch(fetchAllScoreboards({ slug, locale: locale || "en" })),
5252
serverSideTranslations(locale as string),
5353
]);

src/store/feature/learningModules.slice.ts

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ import { HYDRATE } from "next-redux-wrapper";
1313
interface LearningModulesState {
1414
list: LearningModule[];
1515
current?: LearningModule | null;
16+
loading: boolean;
1617
}
1718

1819
const initialState: LearningModulesState = {
1920
list: [],
2021
current: null,
22+
loading: true,
2123
};
2224

2325
export const learningModulesSlice = createSlice({
@@ -30,36 +32,22 @@ export const learningModulesSlice = createSlice({
3032
setLearningModuleList(state, action) {
3133
state.list = action.payload;
3234
},
35+
setLoading(state, action) {
36+
state.loading = action.payload;
37+
},
3338
},
3439
extraReducers: (builder) => {
35-
builder
36-
.addCase(findLearningModule.fulfilled, (state, action) => {
37-
state.current = action.payload;
38-
})
39-
.addCase(getAllLearningModules.fulfilled, (state, action) => {
40-
state.list = action.payload;
41-
})
42-
.addCase(HYDRATE, (state, action) => {
43-
return {
44-
...state,
45-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
46-
//@ts-ignore
47-
...action.payload["learningModules"],
48-
};
49-
});
40+
builder.addCase(HYDRATE, (state, action) => {
41+
return {
42+
...state,
43+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
44+
//@ts-ignore
45+
...action.payload["learningModules"],
46+
};
47+
});
5048
},
5149
});
5250

53-
export const findLearningModule = createAsyncThunk("learningModules/find", async (id: string) => {
54-
const { data } = await api().server.get(`learning-modules/${id}`);
55-
return data;
56-
});
57-
58-
export const getAllLearningModules = createAsyncThunk("learningModules/all", async (slug: string) => {
59-
const { data } = await api().server.get<LearningModule[]>(`courses/${slug}/learning-modules`);
60-
return data;
61-
});
62-
6351
export const submitModuleAnswer = createAsyncThunk("learningModules/submitAnswer", async ({ ref, course }: { ref: string; course: string }) => {
6452
await api().client.put("interactive-modules/answer", {
6553
module: ref,
@@ -75,5 +63,5 @@ export const checkAnswer = async (ref: string) => {
7563
return data;
7664
};
7765

78-
export const { setCurrentLearningModule, setLearningModuleList } = learningModulesSlice.actions;
66+
export const { setCurrentLearningModule, setLearningModuleList, setLoading } = learningModulesSlice.actions;
7967
export default learningModulesSlice;

0 commit comments

Comments
 (0)