Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ Navigate to [localhost:3000](http://localhost:3000) in your preferred browser.
The schemas for the database are documented in the directory `server/models/schema`.
A class diagram for the schema definition is linked below:

https://drive.google.com/file/d/1W0-bXBFXSd81ZJYxVlYHQ--JJetGBdhv/view?usp=sharing
https://drive.google.com/file/d/1c4RFD-MW9UC3w10rGNp_bjD5Y4gq0kTg/view?usp=sharing
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import useCommunityBreadcrumb from '../../../../../hooks/useCommunityBreadcrumb';
import useCommunityDetails from '../../../../../hooks/useCommunityDetails';
import { CommunitySubpageType } from '../../../../../types';
import './communityBreadcrumb.css';

Expand All @@ -23,7 +23,7 @@ const CommunityBreadcrumb = ({
paddingLeftOverride?: number;
}) => {
const { handleNavigateToCommunity, handleNavigateToCommunityList, communityTitle } =
useCommunityBreadcrumb({
useCommunityDetails({
communityID,
objectID,
subPageType,
Expand Down
12 changes: 7 additions & 5 deletions client/src/components/main/questionPage/question/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import './index.css';
import { getMetaData } from '../../../../tool';
Expand All @@ -25,7 +24,10 @@ interface QuestionProps {
*/
const QuestionView = ({ q }: QuestionProps) => {
const navigate = useNavigate();
const community = useCommunityDetails(q.community);
const { handleNavigateToCommunity, communityTitle } = useCommunityDetails({
objectID: q._id,
subPageType: 'Question',
});
const { frame, title } = useEquippedRewards(q.askedBy);

/**
Expand Down Expand Up @@ -76,14 +78,14 @@ const QuestionView = ({ q }: QuestionProps) => {
</button>
))}
</div>
{community && (
{communityTitle && (
<div
className='question_community'
onClick={e => {
e.stopPropagation();
navigate(`/community/${community._id}`);
handleNavigateToCommunity();
}}>
<span className='community_label'>Community:</span> {community.name}
<span className='community_label'>Community:</span> {communityTitle}
</div>
)}
</div>
Expand Down
81 changes: 0 additions & 81 deletions client/src/hooks/useCommunityBreadcrumb.ts

This file was deleted.

91 changes: 67 additions & 24 deletions client/src/hooks/useCommunityDetails.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,80 @@
import { useEffect, useState } from 'react';
import { getCommunityDetails } from '../services/communityService';
import { Community } from '../types';
import { useNavigate } from 'react-router-dom';
import { getCommunityByObjectId, getCommunityDetails } from '../services/communityService';
import { CommunityObjectType, CommunitySubpageType } from '../types';

/**
* Custom hook to fetch and manage community details by ID.
*
* @param communityId - The ID of the community to fetch details for.
* @returns The community details or `null` if not available.
* Hook for handling the logic for retrieving community details for a community object.
* @param communityID - The ID of the community the user is navigating.
* @param objectID - The ID of the object within a community that the user is viewing.
* @param subPageType - The type of subpage the user is in within a community.
* @returns handleNavigateToCommunity - Function that navigates the user to the community page of
* the community with the communityID
* @returns handleNavigateToCommunityList - Function that navigates the user to the community list page
* @returns communityTitle - The title of the community the user is in.
*/
const useCommunityDetails = (communityId?: string) => {
const [community, setCommunity] = useState<Community | null>(null);
const useCommunityDetails = ({
communityID,
objectID,
subPageType,
}: {
communityID?: string;
objectID?: string;
subPageType?: CommunitySubpageType;
}) => {
const navigate = useNavigate();
const [communityTitle, setCommunityTitle] = useState<string>('');
const [fetchedCommuntiyId, setFetchedCommunityId] = useState<string>(communityID || '');

useEffect(() => {
// If communityId is not defined, skip fetching
if (!communityId) {
setCommunity(null);
return;
}

const fetchCommunity = async () => {
try {
const data = await getCommunityDetails(communityId);
setCommunity(data);
} catch (error) {
// eslint-disable-next-line no-console
console.error(`Failed to fetch details for community ID: ${communityId}`, error);
const fetchCommunityTitle = async () => {
if (communityID) {
try {
const community = await getCommunityDetails(communityID);
setCommunityTitle(community.name);
} catch (error) {
// eslint-disable-next-line no-console
console.error('failed to fetch community by id');
}
} else if (objectID) {
try {
// if subPageType is 'Community', 'New Article', or 'New Poll', communityID should already be provided
if (subPageType === 'Article' || subPageType === 'Poll' || subPageType === 'Question') {
const community = await getCommunityByObjectId(
objectID,
subPageType as CommunityObjectType,
);
setCommunityTitle(community.name);
setFetchedCommunityId(community._id!);
}
} catch (error) {
setCommunityTitle('');
}
}
};

fetchCommunity();
}, [communityId]);
fetchCommunityTitle();
}, [communityID, objectID, subPageType]);

/**
* Function to navigate to the community page of the community with communityID
*/
const handleNavigateToCommunity = () => {
navigate(`/community/${fetchedCommuntiyId}`);
};

/**
* Function to navigate to the community list
*/
const handleNavigateToCommunityList = () => {
navigate(`/community`);
};

return community;
return {
handleNavigateToCommunity,
handleNavigateToCommunityList,
communityTitle,
};
};

export default useCommunityDetails;
2 changes: 1 addition & 1 deletion client/src/hooks/useCommunityPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ const useCommunityPage = () => {
}

setSearchedAndSortedArticles(updatedArticles);
}, [articles, articleSortOption, searchedAndSortedArticles, searchBarValue]);
}, [articles, articleSortOption, searchBarValue]);

/**
* Function to handle changes in the input field.
Expand Down
2 changes: 0 additions & 2 deletions client/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export interface Answer {
* - downVotes - An array of usernames who downvoted the question.
* - comments - Comments associated with the question.
* - subscribers - The usernames of subscribed users
* - community - The id of the community that the question belongs to.
*/
export interface Question {
_id?: string;
Expand All @@ -131,7 +130,6 @@ export interface Question {
downVotes: string[];
comments: Comment[];
subscribers: string[];
community?: string;
}

/**
Expand Down
1 change: 0 additions & 1 deletion server/models/schema/question.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ const questionSchema: Schema = new Schema(
downVotes: [{ type: String }],
comments: [{ type: Schema.Types.ObjectId, ref: 'Comment' }],
subscribers: [{ type: String }],
community: { type: Schema.Types.ObjectId, ref: 'Community' },
},
{ collection: 'Question' },
);
Expand Down
33 changes: 12 additions & 21 deletions server/populate_db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,17 +257,6 @@ async function questionCreate(
return await QuestionModel.create(questionDetail);
}

/**
* Associate a community with a Question by updating the Question.
*/
async function associateQuestionWithCommunity(question: Question, community: Community) {
return await QuestionModel.findByIdAndUpdate(
{ _id: question._id },
{ community: community },
{ new: true },
);
}

/**
* Creates a new PollOption document in the database.
*
Expand Down Expand Up @@ -568,14 +557,14 @@ const populate = async () => {
const U3 = await userCreate('abhi3241', 'se35ls($knf^%^gxe', 30, [], [], '', '', [N5_1, N6_1], []);
const U4 = await userCreate('alia', 'OverflowAccount', 0, [], [], '', '', [], []);
const U5 = await userCreate('monkeyABC', 'password', 20, [], [], '', '', [N1_3, N5_2], []);
const U6 = await userCreate('elephantCDE', 'elephantsForLife', 4000, [FRAMES[0].name, FRAMES[1].name], [], '', '', [N6_2, N1_4, N4_2, N6_3], []);
const U6 = await userCreate('elephantCDE', 'elephantsForLife', 4998, [FRAMES[0].name, FRAMES[1].name], [CHAL1_REWARD, CHAL3_REWARD], '', '', [N6_2, N1_4, N4_2, N6_3], []);
const U7 = await userCreate('abaya', '1234567890', 150, [], [], '', '', [N2_3], []);
const U8 = await userCreate('mackson3332', 'verystronglongpassword', 30, [], [], '', '', [N3_2], []);

const po1_promise = [
pollOptionCreate('Windows', [U2.username, U3.username]),
pollOptionCreate('macOS', [U4.username, U5.username, U7.username]),
pollOptionCreate('Linux', [U6.username]),
pollOptionCreate('Linux', []),
pollOptionCreate('Other', []),
];
const p1_options = await Promise.all(po1_promise);
Expand All @@ -596,7 +585,7 @@ const populate = async () => {
];
const p3_options = await Promise.all(po3_promise);

const P1 = await pollCreate(P1_TITLE, p1_options, U1.username, new Date('2024-10-30'), new Date('2024-11-26'), false);
const P1 = await pollCreate(P1_TITLE, p1_options, U1.username, new Date('2024-10-30'), new Date('2024-12-06'), false);
const P2 = await pollCreate(P2_TITLE, p2_options, U2.username, new Date(), new Date('2024-11-23'), false);
const P3 = await pollCreate(P3_TITLE, p3_options, U3.username, new Date(), new Date('2024-11-11'), true);

Expand All @@ -614,9 +603,9 @@ const populate = async () => {

const U9 = await userCreate('communityMember', 'pass1234', 0, [], [], '', '', [N7, N8, N9, N10], []);

const COM1 = await communityCreate('Tech Enthusiasts', [U1, U2, U3, U4, U9].map(u => u.username), [Q4], [P1], [ART1, ART2, ART4, ART5]);
const COM2 = await communityCreate('CS Majors', [U4, U5, U6, U7, U9].map(u => u.username), [Q1, Q2, Q3], [P2, P3], [ART3]);
const COM3 = await communityCreate('Northeastern CS4950', [U8, U4].map(u => u.username), [], [], []);
await communityCreate('Tech Enthusiasts', [U1, U2, U3, U4, U9].map(u => u.username), [Q4], [P1], [ART1, ART2, ART4, ART5]);
await communityCreate('CS Majors', [U4, U5, U6, U7, U9].map(u => u.username), [Q1, Q2, Q3], [P2, P3], [ART3]);
await communityCreate('Northeastern CS4950', [U8, U4].map(u => u.username), [], [], []);

// challenges
const CHAL1 = await challengeCreate(CHAL1_DESCRIPTION, CHAL1_AMT, 'answer', CHAL1_REWARD);
Expand Down Expand Up @@ -645,10 +634,12 @@ const populate = async () => {
await userChallengeCreate(U2.username, CHAL5, []); // in progress (0/10)
await userChallengeCreate(U2.username, CHAL6, [...tenDates, ...tenDates]) // in progress (20/25) (upvotes)

await associateQuestionWithCommunity(Q4, COM1);
await associateQuestionWithCommunity(Q1, COM2);
await associateQuestionWithCommunity(Q2, COM2);
await associateQuestionWithCommunity(Q3, COM2);
await userChallengeCreate(U6.username, CHAL1, [currentDate]); // completed (1/1)
await userChallengeCreate(U6.username, CHAL2, [...fiveDates, currentDate, currentDate, currentDate, currentDate]); // in progress (9/10)
await userChallengeCreate(U6.username, CHAL3, [currentDate]); // completed (1/1)
await userChallengeCreate(U6.username, CHAL4, [currentDate]); // in progress (1/5)
await userChallengeCreate(U6.username, CHAL5, []); // in progress (0/10)
await userChallengeCreate(U6.username, CHAL6, [...tenDates, ...tenDates, currentDate, currentDate, currentDate]) // in progress (23/25) (upvotes)

console.log('Database populated');
} catch (err) {
Expand Down
1 change: 0 additions & 1 deletion server/tests/application.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1916,7 +1916,6 @@ describe('application module', () => {
expect(false).toBeTruthy();
} else {
expect(result._id?.toString()).toBe(fixedQuestionId.toString());
expect(result.community?.toString()).toBe(mockCommunityId.toString());
expect(result.text).toBe('Sample Question');
}
});
Expand Down
2 changes: 0 additions & 2 deletions server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ export interface Tag {
* - downVotes - An array of usernames that have downvoted the question.
* - comments - Object IDs of comments that have been added to the question by users, or comments themselves if populated.
* - subscribers - The usernames of subscribed users
* - community - The community the question belongs to
*/
export interface Question {
_id?: ObjectId;
Expand All @@ -82,7 +81,6 @@ export interface Question {
downVotes: string[];
comments: Comment[] | ObjectId[];
subscribers: string[];
community?: Community;
}

/**
Expand Down