From 109318b7b08dba8b4c5085e83e4639b1b461a091 Mon Sep 17 00:00:00 2001 From: Kristen Liu Date: Thu, 14 Nov 2024 16:40:09 -0500 Subject: [PATCH 01/16] created Community model --- server/controller/community.ts | 25 +++++++++++++ server/data/posts_strings.ts | 11 ++++++ server/models/community.ts | 17 +++++++++ server/models/schema/community.ts | 30 ++++++++++++++++ server/populate_db.ts | 58 ++++++++++++++++++++++++++++++- server/types.ts | 10 ++++++ 6 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 server/controller/community.ts create mode 100644 server/models/community.ts create mode 100644 server/models/schema/community.ts diff --git a/server/controller/community.ts b/server/controller/community.ts new file mode 100644 index 0000000..8742af5 --- /dev/null +++ b/server/controller/community.ts @@ -0,0 +1,25 @@ +import express from 'express'; +import { FakeSOSocket } from '../types'; + +const communityController = (socket: FakeSOSocket) => { + const router = express.Router(); + + // Example route for creating a community (currently no logic implemented) + router.post('/create', (req, res) => { + res.status(501).json({ message: 'Not implemented' }); + }); + + // Example route for retrieving all communities (currently no logic implemented) + router.get('/', (req, res) => { + res.status(501).json({ message: 'Not implemented' }); + }); + + // Example route for retrieving a single community by ID (currently no logic implemented) + router.get('/:id', (req, res) => { + res.status(501).json({ message: 'Not implemented' }); + }); + + return router; +}; + +export default communityController; diff --git a/server/data/posts_strings.ts b/server/data/posts_strings.ts index 120637b..2d96919 100644 --- a/server/data/posts_strings.ts +++ b/server/data/posts_strings.ts @@ -52,6 +52,12 @@ export const T6_NAME = 'website'; export const T6_DESC = 'A website is a collection of interlinked web pages, typically identified with a common domain name, and published on at least one web server. Websites can serve various purposes, such as information sharing, entertainment, commerce, and social networking.'; +export const T7_NAME = 'css'; +export const T7_DESC = + 'Cascading Style Sheets (CSS) is a style sheet language used for describing the presentation of a document written in a markup language like HTML. CSS is a cornerstone technology, alongside HTML and JavaScript.'; +export const T8_NAME = 'aws'; +export const T8_DESC = + 'Amazon Web Services (AWS) is a comprehensive, evolving cloud computing platform provided by Amazon. It offers a mix of infrastructure as a service (IaaS), platform as a service (PaaS), and packaged software as a service (SaaS) offerings.'; export const C1_TEXT = 'This explanation about React Router is really helpful! I never realized it was just a wrapper around history. Thanks!'; export const C2_TEXT = @@ -76,3 +82,8 @@ export const C11_TEXT = 'I found the discussion on SharedPreferences vs apply() very useful. Great explanation of the differences!'; export const C12_TEXT = "I feel like there's so much more to Android Studio that I'm just scratching the surface of. Thanks for sharing your experience!"; +export const FRONT_END_TAGS = [T1_NAME, T6_NAME, T7_NAME]; +// export const BACK_END_TAGS = ['mongodb', 'node.js']; +// export const ML_TAGS = ['neural-networks', 'deep-learning']; +// export const AI_TAGS = ['neural-networks', 'reinforcement-learning', 'pytorch', 'nlp']; +export const CLOUD_TAGS = [T8_NAME, T5_NAME]; // ADD AZURE, GCP diff --git a/server/models/community.ts b/server/models/community.ts new file mode 100644 index 0000000..86572e2 --- /dev/null +++ b/server/models/community.ts @@ -0,0 +1,17 @@ +// Community Document Schema +import mongoose, { Model } from 'mongoose'; +import { Community } from '../types'; +import communitySchema from './schema/community'; + +/** + * Mongoose model for the `Community` collection. + * + * This model is created using the `Community` interface and the `communitySchema`, representing the + * `Community` collection in the MongoDB database, and provides an interface for interacting with + * the stored questions. + * + * @type {Model} + */ +const CommunityModel: Model = mongoose.model('Community', communitySchema); + +export default CommunityModel; diff --git a/server/models/schema/community.ts b/server/models/schema/community.ts new file mode 100644 index 0000000..c8b9985 --- /dev/null +++ b/server/models/schema/community.ts @@ -0,0 +1,30 @@ +import { Schema } from 'mongoose'; +/** + * Mongoose schema for Community. + * + * This schema defines the structure each community. + * Each community includes the following fields: + * - `name`: The name of the community. + * - `tags`: An array of strings with the tag names. + * - `users`: An array of strings of the user's names. + * - `questions`: An array of references to `Question` documents associated with the community. + */ +const communitySchema: Schema = new Schema( + { + name: { + type: String, + }, + tags: { + type: [String], + }, + users: { + type: [String], + }, + questions: { + type: [{ type: Schema.Types.ObjectId, ref: 'Question' }], + }, + }, + { collection: 'Community' }, +); + +export default communitySchema; diff --git a/server/populate_db.ts b/server/populate_db.ts index e8b601c..869e680 100644 --- a/server/populate_db.ts +++ b/server/populate_db.ts @@ -2,7 +2,8 @@ import mongoose from 'mongoose'; import AnswerModel from './models/answers'; import QuestionModel from './models/questions'; import TagModel from './models/tags'; -import { Answer, Comment, Question, Tag } from './types'; +import CommunityModel from './models/community'; +import { Answer, Comment, Question, Tag, Community } from './types'; import { Q1_DESC, Q1_TXT, @@ -44,6 +45,15 @@ import { C10_TEXT, C11_TEXT, C12_TEXT, + FRONT_END_TAGS, + // BACK_END_TAGS, + // ML_TAGS, + // AI_TAGS, + CLOUD_TAGS, + T7_NAME, + T7_DESC, + T8_NAME, + T8_DESC, } from './data/posts_strings'; import CommentModel from './models/comments'; @@ -173,6 +183,36 @@ async function questionCreate( return await QuestionModel.create(questionDetail); } +/** + * Fetches questions from the database based on the tags provided. + * + * @param tags An array of tags to search for. + * @returns A Promise that resolves to an array of Question documents. + */ +async function getQuestionsByTags(tags: Tag[]): Promise { + return await QuestionModel.find({ tags: { $in: tags } }); +} + +/** + * Creates a new Community document in the database. + * @param name The name of the community. + * @param tags The tags associated with the community. + * @param users The users who are part of the community. + * @param questions The questions that have been asked in the community. + * @returns A Promise that resolves to the created Community document. + * @throws An error if any of the parameters are invalid. + */ +async function communityCreate(name: string, tags: string[], users: string[], questions: Question[]): Promise { + if (name === '' || tags.length === 0) throw new Error('Invalid Community Format'); + const community: Community = { + name: name, + tags: tags, + users: users, + questions: questions, + }; + return await CommunityModel.create(community); +} + /** * Populates the database with predefined data. * Logs the status of the operation to the console. @@ -185,6 +225,9 @@ const populate = async () => { const t4 = await tagCreate(T4_NAME, T4_DESC); const t5 = await tagCreate(T5_NAME, T5_DESC); const t6 = await tagCreate(T6_NAME, T6_DESC); + const t7 = await tagCreate(T7_NAME, T7_DESC); + const t8 = await tagCreate(T8_NAME, T8_DESC); + const c1 = await commentCreate(C1_TEXT, 'sana', new Date('2023-12-12T03:30:00')); const c2 = await commentCreate(C2_TEXT, 'ihba001', new Date('2023-12-01T15:24:19')); @@ -249,6 +292,18 @@ const populate = async () => { [c12], ); + const frontEndQuestions = await getQuestionsByTags([t1, t6, t7]); + // const backEndQuestions = await getQuestionsByTags(BACK_END_TAGS); + // const machineLearningQuestions = await getQuestionsByTags(ML_TAGS); + // const aiQuestions = await getQuestionsByTags(AI_TAGS); + const cloudQuestions = await getQuestionsByTags([t5, t8]); + + await communityCreate('front-end-development', FRONT_END_TAGS, [], frontEndQuestions); + // await communityCreate('back-end-development', BACK_END_TAGS, [], backEndQuestions); + // await communityCreate('machine learning', ML_TAGS, [], machineLearningQuestions); + // await communityCreate('ai', AI_TAGS, [], aiQuestions); + await communityCreate('cloud computing', CLOUD_TAGS, [], cloudQuestions); + console.log('Database populated'); } catch (err) { console.log('ERROR: ' + err); @@ -256,6 +311,7 @@ const populate = async () => { if (db) db.close(); console.log('done'); } + }; populate(); diff --git a/server/types.ts b/server/types.ts index 651291d..bd119b1 100644 --- a/server/types.ts +++ b/server/types.ts @@ -9,6 +9,16 @@ export type FakeSOSocket = Server; */ export type OrderType = 'newest' | 'unanswered' | 'active' | 'mostViewed'; +/** + * Interface representing Community + */ +export interface Community { + name: string; + tags: string[]; + users: string[]; + questions: Question[]; +} + /** * Interface representing an Answer document, which contains: * - _id - The unique identifier for the answer. Optional field From 5dc434c52a1cf2b3fabd974ab9b54c9330a2c26b Mon Sep 17 00:00:00 2001 From: Kristen Liu Date: Fri, 15 Nov 2024 15:11:21 -0500 Subject: [PATCH 02/16] community changes --- client/src/components/fakestackoverflow.tsx | 6 +- .../chooseCommunityPage/chooseCommunity.tsx | 82 +++++++ .../newUser/chooseCommunityPage/index.tsx | 220 +++++++++--------- client/src/hooks/useCommunityNames.ts | 38 +++ client/src/services/communityService.ts | 19 ++ client/src/types.ts | 15 ++ 6 files changed, 268 insertions(+), 112 deletions(-) create mode 100644 client/src/components/login/newUser/chooseCommunityPage/chooseCommunity.tsx create mode 100644 client/src/hooks/useCommunityNames.ts create mode 100644 client/src/services/communityService.ts diff --git a/client/src/components/fakestackoverflow.tsx b/client/src/components/fakestackoverflow.tsx index e9e6d28..4235e89 100644 --- a/client/src/components/fakestackoverflow.tsx +++ b/client/src/components/fakestackoverflow.tsx @@ -19,7 +19,8 @@ import CommunityInfo from './main/profile/community'; import StatusInfo from './main/profile/status'; import ChooseTagsPage from './login/newUser/chooseTagsPage/index'; import CommunityHomePage from './main/homePage/community'; -import PostLoginCommunity from './login/newUser/chooseCommunityPage'; +// import PostLoginCommunity from './login/newUser/chooseCommunityPage'; +import ChooseCommunityPage from './login/newUser/chooseCommunityPage/chooseCommunity'; const ProtectedRoute = ({ user, @@ -54,7 +55,8 @@ const FakeStackOverflow = ({ socket }: { socket: FakeSOSocket | null }) => { } /> } + // element={} + element={} /> {/* Protected Routes */} { diff --git a/client/src/components/login/newUser/chooseCommunityPage/chooseCommunity.tsx b/client/src/components/login/newUser/chooseCommunityPage/chooseCommunity.tsx new file mode 100644 index 0000000..b451869 --- /dev/null +++ b/client/src/components/login/newUser/chooseCommunityPage/chooseCommunity.tsx @@ -0,0 +1,82 @@ +/* eslint-disable no-console */ +import React, { useState } from 'react'; +import './index.css'; +import { NavLink } from 'react-router-dom'; +import { doc, setDoc } from 'firebase/firestore'; +// eslint-disable-next-line import/no-extraneous-dependencies +// import useTagNames from '../../../../hooks/useTagNames'; +import { db, auth } from '../../../../firebaseConfig'; +import logo from '../../../../logo.svg'; +import useCommunityNames from '../../../../hooks/useCommunityNames'; + +/** + * Depicts tags that the user can choose from. + */ +const ChooseCommunityPage = () => { + const { communityNames } = useCommunityNames(); + const [selectedCommunity, setSelectedCommunity] = useState(''); + + const handleCommunityClick = (communityName: string) => { + setSelectedCommunity(prevCommunity => (prevCommunity === communityName ? '' : communityName)); + }; + + const saveCommunityToUserAccount = async (community: string) => { + try { + const user = auth.currentUser; + if (user) { + console.log(user.email); + if (user.email) { + const userRef = doc(db, 'users', user.email); + await setDoc( + userRef, + { + username: user.email, + community, + }, + { merge: true }, + ); + } else { + console.error('Error saving community'); + } + } else { + console.error('Error saving community'); + } + } catch (error) { + console.error('Error saving community:', error); + } + }; + + return ( +
+ Fake Stack Overflow Logo +
+

Recommended Communities:

+
+
+ {communityNames && + communityNames.map(community => ( +
  • handleCommunityClick(community.name)}> + {community.name} +
  • + ))} +
    +
    + +
    +
    + ); +}; + +export default ChooseCommunityPage; diff --git a/client/src/components/login/newUser/chooseCommunityPage/index.tsx b/client/src/components/login/newUser/chooseCommunityPage/index.tsx index c8ece11..b2910dd 100644 --- a/client/src/components/login/newUser/chooseCommunityPage/index.tsx +++ b/client/src/components/login/newUser/chooseCommunityPage/index.tsx @@ -1,110 +1,110 @@ -/* eslint-disable no-console */ -import React, { useEffect, useState } from 'react'; -import { collection, query, getDoc, getDocs, doc, updateDoc } from 'firebase/firestore'; -import { NavLink } from 'react-router-dom'; -import { db } from '../../../../firebaseConfig'; -import './index.css'; - -const PostLoginCommunity = ({ userId }: { userId: string }) => { - const [userTags, setUserTags] = useState([]); - const [suggestedCommunities, setSuggestedCommunities] = useState([]); - const [selectedCommunity, setSelectedCommunity] = useState(null); - - useEffect(() => { - const fetchUserTags = async () => { - const userRef = doc(db, 'users', userId); - const docSnap = await getDoc(userRef); - - if (docSnap.exists()) { - setUserTags(docSnap.data().tags || []); - } else { - console.log('User not found!'); - } - }; - - fetchUserTags(); - }, [userId]); - - useEffect(() => { - if (userTags.length === 0) return; - - const fetchSuggestedCommunities = async () => { - const communitiesRef = collection(db, 'communities'); - const q = query(communitiesRef); - - const querySnapshot = await getDocs(q); - const matchedCommunities: string[] = []; - - // eslint-disable-next-line @typescript-eslint/no-shadow - querySnapshot.forEach(doc => { - const community = doc.data(); - const commonTags = community.tags.filter((tag: string) => userTags.includes(tag)); - - // if there are common tags with a community, suggest that community -- can change - // implementation - if (commonTags.length > 0) { - matchedCommunities.push(doc.id); - } - }); - - setSuggestedCommunities(matchedCommunities); - }; - - fetchSuggestedCommunities(); - }, [userTags]); - - const handleCommunitySelect = async (community: string) => { - setSelectedCommunity(community); - const userRef = doc(db, 'users', userId); - - try { - const docSnap = await getDoc(userRef); - if (!docSnap.exists()) { - console.log('User not found!'); - return; - } - const userData = docSnap.data(); - const communitySelected = userData.communitySelected || []; - - // users can only select one community: - if (communitySelected.length === 0 || communitySelected[0] !== community) { - await updateDoc(userRef, { - communitySelected: [community], - }); - console.log(`Community "${community}" added to user's selected communities`); - } else { - console.log(`Community "${community}" is already selected.`); - } - } catch (error) { - console.error('Error adding community to user:', error); - } - }; - - return ( -
    -

    - We recommend the following communities based on your interests: -

    -
      - {suggestedCommunities.map(community => ( -
    • handleCommunitySelect(community)} - className={selectedCommunity === community ? 'selected' : ''}> - {community} -
    • - ))} -
    -

    -
    - -
    -
    - ); -}; - -export default PostLoginCommunity; +// /* eslint-disable no-console */ +// import React, { useEffect, useState } from 'react'; +// import { collection, query, getDoc, getDocs, doc, updateDoc } from 'firebase/firestore'; +// import { NavLink } from 'react-router-dom'; +// import { db } from '../../../../firebaseConfig'; +// import './index.css'; + +// const PostLoginCommunity = ({ userId }: { userId: string }) => { +// const [userTags, setUserTags] = useState([]); +// const [suggestedCommunities, setSuggestedCommunities] = useState([]); +// const [selectedCommunity, setSelectedCommunity] = useState(null); + +// useEffect(() => { +// const fetchUserTags = async () => { +// const userRef = doc(db, 'users', userId); +// const docSnap = await getDoc(userRef); + +// if (docSnap.exists()) { +// setUserTags(docSnap.data().tags || []); +// } else { +// console.log('User not found!'); +// } +// }; + +// fetchUserTags(); +// }, [userId]); + +// useEffect(() => { +// if (userTags.length === 0) return; + +// const fetchSuggestedCommunities = async () => { +// const communitiesRef = collection(db, 'communities'); +// const q = query(communitiesRef); + +// const querySnapshot = await getDocs(q); +// const matchedCommunities: string[] = []; + +// // eslint-disable-next-line @typescript-eslint/no-shadow +// querySnapshot.forEach(doc => { +// const community = doc.data(); +// const commonTags = community.tags.filter((tag: string) => userTags.includes(tag)); + +// // if there are common tags with a community, suggest that community -- can change +// // implementation +// if (commonTags.length > 0) { +// matchedCommunities.push(doc.id); +// } +// }); + +// setSuggestedCommunities(matchedCommunities); +// }; + +// fetchSuggestedCommunities(); +// }, [userTags]); + +// const handleCommunitySelect = async (community: string) => { +// setSelectedCommunity(community); +// const userRef = doc(db, 'users', userId); + +// try { +// const docSnap = await getDoc(userRef); +// if (!docSnap.exists()) { +// console.log('User not found!'); +// return; +// } +// const userData = docSnap.data(); +// const communitySelected = userData.communitySelected || []; + +// // users can only select one community: +// if (communitySelected.length === 0 || communitySelected[0] !== community) { +// await updateDoc(userRef, { +// communitySelected: [community], +// }); +// console.log(`Community "${community}" added to user's selected communities`); +// } else { +// console.log(`Community "${community}" is already selected.`); +// } +// } catch (error) { +// console.error('Error adding community to user:', error); +// } +// }; + +// return ( +//
    +//

    +// We recommend the following communities based on your interests: +//

    +//
      +// {suggestedCommunities.map(community => ( +//
    • handleCommunitySelect(community)} +// className={selectedCommunity === community ? 'selected' : ''}> +// {community} +//
    • +// ))} +//
    +//

    +//
    +// +//
    +//
    +// ); +// }; + +// export default PostLoginCommunity; diff --git a/client/src/hooks/useCommunityNames.ts b/client/src/hooks/useCommunityNames.ts new file mode 100644 index 0000000..8d51f54 --- /dev/null +++ b/client/src/hooks/useCommunityNames.ts @@ -0,0 +1,38 @@ +import { useEffect, useState } from 'react'; +import { getCommunityNames } from '../services/communityService'; +import { Community } from '../types'; + +/** + * Custom hook to handle fetching community details by community name. + * + * @param t - The tag object to fetch data for + * + * @returns community - The current community details. + * @returns setCommunity - Setter to manually update the community state if needed. + */ +const useCommunityNames = () => { + const [communityNames, setCommunityNames] = useState([]); + + useEffect(() => { + const fetchData = async () => { + try { + const res = await getCommunityNames(); + if (Array.isArray(res)) { + setCommunityNames(res); + } else { + setCommunityNames([]); + } + } catch (e) { + // eslint-disable-next-line no-console + console.log(e); + } + }; + fetchData(); + }); + + return { + communityNames, + }; +}; + +export default useCommunityNames; diff --git a/client/src/services/communityService.ts b/client/src/services/communityService.ts new file mode 100644 index 0000000..a49587f --- /dev/null +++ b/client/src/services/communityService.ts @@ -0,0 +1,19 @@ +/* eslint-disable import/prefer-default-export */ +import api from './config'; +import { Community } from '../types'; + +const COMMUNITY_API_URL = `${process.env.REACT_APP_SERVER_URL}/community`; + +/** + * ADD TESTS?????? + * @returns names of communities + */ +const getCommunityNames = async (): Promise => { + const res = await api.get(`${COMMUNITY_API_URL}/getCommunityNames`); + if (res.status !== 200) { + throw new Error(`Error when fetching community names`); + } + return res.data; +}; + +export { getCommunityNames }; diff --git a/client/src/types.ts b/client/src/types.ts index 651f70a..80047fb 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -149,3 +149,18 @@ export interface ServerToClientEvents { voteUpdate: (vote: VoteUpdatePayload) => void; commentUpdate: (update: CommentUpdatePayload) => void; } + +/** + * Interface representing Community. + * + * - name - The name of the community. + * - tags - An array of strings with the tag names. + * - users - An array of strings of the user's names. + * - questions - An array of references to `Question` documents associated with the community. + */ +export interface Community { + name: string; + tags: string[]; + users: string[]; + questions: Question[]; +} From 21c3be6ba29403a1d918dbc7aa2f43635f9aef71 Mon Sep 17 00:00:00 2001 From: g-pooja-03 Date: Fri, 15 Nov 2024 15:43:40 -0500 Subject: [PATCH 03/16] community fix --- server/controller/community.ts | 43 +++++++++++-------- .../models/{community.ts => communities.ts} | 0 server/populate_db.ts | 2 +- 3 files changed, 27 insertions(+), 18 deletions(-) rename server/models/{community.ts => communities.ts} (100%) diff --git a/server/controller/community.ts b/server/controller/community.ts index 8742af5..ddb23e9 100644 --- a/server/controller/community.ts +++ b/server/controller/community.ts @@ -1,23 +1,32 @@ -import express from 'express'; -import { FakeSOSocket } from '../types'; +import express, { Request, Response, Router } from 'express'; +import CommunityModel from '../models/communities'; -const communityController = (socket: FakeSOSocket) => { - const router = express.Router(); +const communityController = () => { + const router: Router = express.Router(); - // Example route for creating a community (currently no logic implemented) - router.post('/create', (req, res) => { - res.status(501).json({ message: 'Not implemented' }); - }); + /** + * Retrieves a list of tags along with the number of questions associated with each tag. + * If there is an error, the HTTP response's status is updated. + * + * @param _ The HTTP request object (not used in this function). + * @param res The HTTP response object used to send back the tag count mapping. + * + * @returns A Promise that resolves to void. + */ + /** + * @param req The Request object containing the tag name in the URL parameters. + * @param res The HTTP response object used to send back the result of the operation. + */ + const getCommunityNames = async (req: Request, res: Response): Promise => { + try { + const communities = await CommunityModel.find({}); // Retrieve only necessary fields + res.json(communities); + } catch (error) { + res.status(500).json({ error: 'Failed to retrieve communities' }); + } + }; - // Example route for retrieving all communities (currently no logic implemented) - router.get('/', (req, res) => { - res.status(501).json({ message: 'Not implemented' }); - }); - - // Example route for retrieving a single community by ID (currently no logic implemented) - router.get('/:id', (req, res) => { - res.status(501).json({ message: 'Not implemented' }); - }); + router.get('/getCommunityNames', getCommunityNames); // so that we can show all tags in the frontend return router; }; diff --git a/server/models/community.ts b/server/models/communities.ts similarity index 100% rename from server/models/community.ts rename to server/models/communities.ts diff --git a/server/populate_db.ts b/server/populate_db.ts index 869e680..7ea895f 100644 --- a/server/populate_db.ts +++ b/server/populate_db.ts @@ -2,7 +2,7 @@ import mongoose from 'mongoose'; import AnswerModel from './models/answers'; import QuestionModel from './models/questions'; import TagModel from './models/tags'; -import CommunityModel from './models/community'; +import CommunityModel from './models/communities'; import { Answer, Comment, Question, Tag, Community } from './types'; import { Q1_DESC, From ba50d2c070d0df191eaf94da312b3c9f047fcd61 Mon Sep 17 00:00:00 2001 From: g-pooja-03 Date: Fri, 15 Nov 2024 16:28:34 -0500 Subject: [PATCH 04/16] style fixes --- client/src/components/fakestackoverflow.tsx | 2 +- .../chooseCommunityPage/chooseCommunity.tsx | 82 -------- .../newUser/chooseCommunityPage/index.css | 86 +++++--- .../newUser/chooseCommunityPage/index.tsx | 190 ++++++++---------- server/app.ts | 2 + 5 files changed, 136 insertions(+), 226 deletions(-) delete mode 100644 client/src/components/login/newUser/chooseCommunityPage/chooseCommunity.tsx diff --git a/client/src/components/fakestackoverflow.tsx b/client/src/components/fakestackoverflow.tsx index 4235e89..c30bcc8 100644 --- a/client/src/components/fakestackoverflow.tsx +++ b/client/src/components/fakestackoverflow.tsx @@ -20,7 +20,7 @@ import StatusInfo from './main/profile/status'; import ChooseTagsPage from './login/newUser/chooseTagsPage/index'; import CommunityHomePage from './main/homePage/community'; // import PostLoginCommunity from './login/newUser/chooseCommunityPage'; -import ChooseCommunityPage from './login/newUser/chooseCommunityPage/chooseCommunity'; +import ChooseCommunityPage from './login/newUser/chooseCommunityPage'; const ProtectedRoute = ({ user, diff --git a/client/src/components/login/newUser/chooseCommunityPage/chooseCommunity.tsx b/client/src/components/login/newUser/chooseCommunityPage/chooseCommunity.tsx deleted file mode 100644 index b451869..0000000 --- a/client/src/components/login/newUser/chooseCommunityPage/chooseCommunity.tsx +++ /dev/null @@ -1,82 +0,0 @@ -/* eslint-disable no-console */ -import React, { useState } from 'react'; -import './index.css'; -import { NavLink } from 'react-router-dom'; -import { doc, setDoc } from 'firebase/firestore'; -// eslint-disable-next-line import/no-extraneous-dependencies -// import useTagNames from '../../../../hooks/useTagNames'; -import { db, auth } from '../../../../firebaseConfig'; -import logo from '../../../../logo.svg'; -import useCommunityNames from '../../../../hooks/useCommunityNames'; - -/** - * Depicts tags that the user can choose from. - */ -const ChooseCommunityPage = () => { - const { communityNames } = useCommunityNames(); - const [selectedCommunity, setSelectedCommunity] = useState(''); - - const handleCommunityClick = (communityName: string) => { - setSelectedCommunity(prevCommunity => (prevCommunity === communityName ? '' : communityName)); - }; - - const saveCommunityToUserAccount = async (community: string) => { - try { - const user = auth.currentUser; - if (user) { - console.log(user.email); - if (user.email) { - const userRef = doc(db, 'users', user.email); - await setDoc( - userRef, - { - username: user.email, - community, - }, - { merge: true }, - ); - } else { - console.error('Error saving community'); - } - } else { - console.error('Error saving community'); - } - } catch (error) { - console.error('Error saving community:', error); - } - }; - - return ( -
    - Fake Stack Overflow Logo -
    -

    Recommended Communities:

    -
    -
    - {communityNames && - communityNames.map(community => ( -
  • handleCommunityClick(community.name)}> - {community.name} -
  • - ))} -
    -
    - -
    -
    - ); -}; - -export default ChooseCommunityPage; diff --git a/client/src/components/login/newUser/chooseCommunityPage/index.css b/client/src/components/login/newUser/chooseCommunityPage/index.css index b1dd2e9..b31a521 100644 --- a/client/src/components/login/newUser/chooseCommunityPage/index.css +++ b/client/src/components/login/newUser/chooseCommunityPage/index.css @@ -3,75 +3,95 @@ flex-direction: column; align-items: center; justify-content: center; + width: 100%; min-height: 100vh; - text-align: center; padding: 20px; - position: relative; + background-color: #f5f5f5; } .recommendation-header { - margin-top: -40px; - font-size: 24px; - margin-bottom: 20px; + font-size: 26px; + font-weight: bold; + color: #333; + margin-bottom: 30px; } -.communities { +.community-list { display: flex; + flex-direction: row; + align-items: center; + gap: 15px; + width: 100%; flex-wrap: wrap; justify-content: center; - gap: 15px; - margin-bottom: 20px; + margin-bottom: 200px; } -.communities li { - background-color: #895159; +.community-pill { + background-color: #6f4046; color: white; - border-radius: 8px; - padding: 1px; - width: 150px; - height: 55px; + border-radius: 50px; + margin: 5px; + padding: 5px 10px; + width: 160px; + height: 50px; text-align: center; - font-size: 17px; + font-size: 16px; display: flex; align-items: center; justify-content: center; + border: none; + transition: background-color 0.3s, transform 0.2s; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); } -.communities li:hover { - background-color: #6f4046; - color: white; -} - -.communities li.selected { - background-color: #ffffff; - color: #6f4046; - border: 2px solid #6f4046; +.community-pill:hover { + background-color: #895159; + transform: scale(1.05); } -.choose-more-text { - font-size: 18px; - margin-top: 50px; - font-weight: bold; +.community-pill.selected { + background-color: #ffffff; + color: #6f4046; + border: 2px solid #6f4046; + box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15); } +/* Button container and alignment */ .button-container { - position: absolute; - bottom: 70px; - right: 40px; + display: flex; + justify-content: flex-end; + width: 100%; + margin-bottom: 20px; } +/* Button styles */ .next-button { - padding: 10px 20px; + padding: 12px 25px; font-size: 16px; cursor: pointer; background-color: #466694; - width: 150px; + width: 160px; height: 45px; color: white; border: none; border-radius: 5px; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + transition: background-color 0.3s, transform 0.2s; } .next-button:hover { + background-color: #324b73; + transform: translateY(-2px); +} + +.next-button:active { background-color: #466694; + transform: translateY(0); +} + +.button-text { + text-decoration: none; + color: white; + font-weight: bold; } diff --git a/client/src/components/login/newUser/chooseCommunityPage/index.tsx b/client/src/components/login/newUser/chooseCommunityPage/index.tsx index b2910dd..2c946ff 100644 --- a/client/src/components/login/newUser/chooseCommunityPage/index.tsx +++ b/client/src/components/login/newUser/chooseCommunityPage/index.tsx @@ -1,110 +1,80 @@ -// /* eslint-disable no-console */ -// import React, { useEffect, useState } from 'react'; -// import { collection, query, getDoc, getDocs, doc, updateDoc } from 'firebase/firestore'; -// import { NavLink } from 'react-router-dom'; -// import { db } from '../../../../firebaseConfig'; -// import './index.css'; - -// const PostLoginCommunity = ({ userId }: { userId: string }) => { -// const [userTags, setUserTags] = useState([]); -// const [suggestedCommunities, setSuggestedCommunities] = useState([]); -// const [selectedCommunity, setSelectedCommunity] = useState(null); - -// useEffect(() => { -// const fetchUserTags = async () => { -// const userRef = doc(db, 'users', userId); -// const docSnap = await getDoc(userRef); - -// if (docSnap.exists()) { -// setUserTags(docSnap.data().tags || []); -// } else { -// console.log('User not found!'); -// } -// }; - -// fetchUserTags(); -// }, [userId]); - -// useEffect(() => { -// if (userTags.length === 0) return; - -// const fetchSuggestedCommunities = async () => { -// const communitiesRef = collection(db, 'communities'); -// const q = query(communitiesRef); - -// const querySnapshot = await getDocs(q); -// const matchedCommunities: string[] = []; - -// // eslint-disable-next-line @typescript-eslint/no-shadow -// querySnapshot.forEach(doc => { -// const community = doc.data(); -// const commonTags = community.tags.filter((tag: string) => userTags.includes(tag)); - -// // if there are common tags with a community, suggest that community -- can change -// // implementation -// if (commonTags.length > 0) { -// matchedCommunities.push(doc.id); -// } -// }); - -// setSuggestedCommunities(matchedCommunities); -// }; - -// fetchSuggestedCommunities(); -// }, [userTags]); - -// const handleCommunitySelect = async (community: string) => { -// setSelectedCommunity(community); -// const userRef = doc(db, 'users', userId); - -// try { -// const docSnap = await getDoc(userRef); -// if (!docSnap.exists()) { -// console.log('User not found!'); -// return; -// } -// const userData = docSnap.data(); -// const communitySelected = userData.communitySelected || []; - -// // users can only select one community: -// if (communitySelected.length === 0 || communitySelected[0] !== community) { -// await updateDoc(userRef, { -// communitySelected: [community], -// }); -// console.log(`Community "${community}" added to user's selected communities`); -// } else { -// console.log(`Community "${community}" is already selected.`); -// } -// } catch (error) { -// console.error('Error adding community to user:', error); -// } -// }; - -// return ( -//
    -//

    -// We recommend the following communities based on your interests: -//

    -//
      -// {suggestedCommunities.map(community => ( -//
    • handleCommunitySelect(community)} -// className={selectedCommunity === community ? 'selected' : ''}> -// {community} -//
    • -// ))} -//
    -//

    -//
    -// -//
    -//
    -// ); -// }; - -// export default PostLoginCommunity; +/* eslint-disable no-console */ +import React, { useState } from 'react'; +import './index.css'; +import { NavLink } from 'react-router-dom'; +import { doc, setDoc } from 'firebase/firestore'; +import { db, auth } from '../../../../firebaseConfig'; +import logo from '../../../../logo.svg'; +import useCommunityNames from '../../../../hooks/useCommunityNames'; + +/** + * Depicts communities that the user can choose from. + */ +const ChooseCommunityPage = () => { + const { communityNames } = useCommunityNames(); + const [selectedCommunity, setSelectedCommunity] = useState(''); + + const handleCommunityClick = (communityName: string) => { + setSelectedCommunity(prevCommunity => (prevCommunity === communityName ? '' : communityName)); + }; + + const saveCommunityToUserAccount = async (community: string) => { + try { + const user = auth.currentUser; + if (user) { + console.log(user.email); + if (user.email) { + const userRef = doc(db, 'users', user.email); + await setDoc( + userRef, + { + username: user.email, + community, + }, + { merge: true }, + ); + } else { + console.error('Error saving community'); + } + } else { + console.error('Error saving community'); + } + } catch (error) { + console.error('Error saving community:', error); + } + }; + + return ( +
    + Fake Stack Overflow Logo +
    +

    Recommended Communities:

    +
    +
    + {communityNames && + communityNames.map(community => ( +
  • handleCommunityClick(community.name)}> + {community.name} +
  • + ))} +
    +
    + +
    +
    + ); +}; + +export default ChooseCommunityPage; diff --git a/server/app.ts b/server/app.ts index 77e0f8a..6e4e469 100644 --- a/server/app.ts +++ b/server/app.ts @@ -13,6 +13,7 @@ import answerController from './controller/answer'; import questionController from './controller/question'; import tagController from './controller/tag'; import commentController from './controller/comment'; +import communityController from './controller/community'; import { FakeSOSocket } from './types'; dotenv.config(); @@ -72,6 +73,7 @@ app.use('/question', questionController(socket)); app.use('/tag', tagController()); app.use('/answer', answerController(socket)); app.use('/comment', commentController(socket)); +app.use('/community', communityController()); // Export the app instance export { app, server, startServer }; From 48cb14e42eb4506d21de2d182729b9184e7285f6 Mon Sep 17 00:00:00 2001 From: Kristen Liu Date: Fri, 15 Nov 2024 17:22:00 -0500 Subject: [PATCH 05/16] inital commit for user model --- client/src/components/fakestackoverflow.tsx | 2 +- client/src/hooks/useCreateUser.ts | 2 +- client/src/hooks/useLogin.ts | 2 +- client/src/types.ts | 4 ++ server/app.ts | 2 + server/controller/user.ts | 10 +++++ server/models/schema/user.ts | 41 +++++++++++++++++++++ server/models/users.ts | 17 +++++++++ server/populate_db.ts | 26 +++++++++++-- server/types.ts | 12 ++++++ 10 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 server/controller/user.ts create mode 100644 server/models/schema/user.ts create mode 100644 server/models/users.ts diff --git a/client/src/components/fakestackoverflow.tsx b/client/src/components/fakestackoverflow.tsx index c30bcc8..3252111 100644 --- a/client/src/components/fakestackoverflow.tsx +++ b/client/src/components/fakestackoverflow.tsx @@ -75,7 +75,7 @@ const FakeStackOverflow = ({ socket }: { socket: FakeSOSocket | null }) => { }> } /> } /> - } /> + } /> } /> diff --git a/client/src/hooks/useCreateUser.ts b/client/src/hooks/useCreateUser.ts index ee5b4c9..f48a160 100644 --- a/client/src/hooks/useCreateUser.ts +++ b/client/src/hooks/useCreateUser.ts @@ -39,7 +39,7 @@ const useCreateUser = () => { try { const { user } = await createUserWithEmailAndPassword(auth, email, password); setIsLoading(false); - setUser({ username: user.email ?? '', status: 'low' }); + // setUser({ username: user.email ?? '', status: 'low' }); // navigate('/home'); navigate('/new/tagselection'); } catch (error) { diff --git a/client/src/hooks/useLogin.ts b/client/src/hooks/useLogin.ts index c906bbe..3f184a7 100644 --- a/client/src/hooks/useLogin.ts +++ b/client/src/hooks/useLogin.ts @@ -45,7 +45,7 @@ const useLogin = () => { event.preventDefault(); try { const { user } = await signInWithEmailAndPassword(auth, email, password); - setUser({ username: user.email ?? '', status: 'low' }); + // setUser({ username: user.email ?? '', status: 'low' }); navigate('/home'); } catch (error) { setErrorMessage((error as Error).message); diff --git a/client/src/types.ts b/client/src/types.ts index 80047fb..3e1618e 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -7,6 +7,10 @@ export type FakeSOSocket = Socket; */ export interface User { username: string; + firstName: string; + lastName: string; + tags: Tag[]; + community: Community; status: string; } diff --git a/server/app.ts b/server/app.ts index 6e4e469..e3d3de1 100644 --- a/server/app.ts +++ b/server/app.ts @@ -15,6 +15,7 @@ import tagController from './controller/tag'; import commentController from './controller/comment'; import communityController from './controller/community'; import { FakeSOSocket } from './types'; +import userController from './controller/user'; dotenv.config(); @@ -74,6 +75,7 @@ app.use('/tag', tagController()); app.use('/answer', answerController(socket)); app.use('/comment', commentController(socket)); app.use('/community', communityController()); +app.use('/user', userController()); // Export the app instance export { app, server, startServer }; diff --git a/server/controller/user.ts b/server/controller/user.ts new file mode 100644 index 0000000..137cc51 --- /dev/null +++ b/server/controller/user.ts @@ -0,0 +1,10 @@ +import express, { Request, Response, Router } from 'express'; +import UserModel from '../models/communities'; + +const userController = () => { + const router: Router = express.Router(); + + return router; +}; + +export default userController; diff --git a/server/models/schema/user.ts b/server/models/schema/user.ts new file mode 100644 index 0000000..8afe78e --- /dev/null +++ b/server/models/schema/user.ts @@ -0,0 +1,41 @@ +import { Schema } from 'mongoose'; + +/** + * Mongoose schema for the Tag collection. + * + * This schema defines the structure for storing tags in the database. + * Each tag includes the following fields: + * - `name`: The name of the tag. This field is required. + * - `description`: A brief description of the tag. This field is required. + */ +const userSchema: Schema = new Schema( + { + username: { + type: String, + required: true, + }, + firstName: { + type: String, + required: true, + }, + lastName: { + type: String, + required: true, + }, + tags: { + type: [{ type: Schema.Types.ObjectId, ref: 'Tag' }], + required: true, + }, + community: { + type: { type: Schema.Types.ObjectId, ref: 'Community' }, + required: true, + }, + status: { + type: String, + required: true, + }, + }, + { collection: 'User' }, +); + +export default userSchema; diff --git a/server/models/users.ts b/server/models/users.ts new file mode 100644 index 0000000..4c39e6b --- /dev/null +++ b/server/models/users.ts @@ -0,0 +1,17 @@ +// Community Document Schema +import mongoose, { Model } from 'mongoose'; +import { User } from '../types'; +import userSchema from './schema/community'; + +/** + * Mongoose model for the `Community` collection. + * + * This model is created using the `Community` interface and the `communitySchema`, representing the + * `Community` collection in the MongoDB database, and provides an interface for interacting with + * the stored questions. + * + * @type {Model} + */ +const UserModel: Model = mongoose.model('User', userSchema); + +export default UserModel; diff --git a/server/populate_db.ts b/server/populate_db.ts index 7ea895f..ccf89b2 100644 --- a/server/populate_db.ts +++ b/server/populate_db.ts @@ -3,7 +3,8 @@ import AnswerModel from './models/answers'; import QuestionModel from './models/questions'; import TagModel from './models/tags'; import CommunityModel from './models/communities'; -import { Answer, Comment, Question, Tag, Community } from './types'; +import UserModel from './models/users'; +import { Answer, Comment, Question, Tag, Community, User } from './types'; import { Q1_DESC, Q1_TXT, @@ -213,6 +214,22 @@ async function communityCreate(name: string, tags: string[], users: string[], qu return await CommunityModel.create(community); } +/** + * FIX THIS COMMENT + */ +async function userCreate(username: string, firstName: string, lastName: string, tags: Tag[], community: Community, status: string): Promise { + if (firstName === '' || lastName === '' || tags.length === 0 || status === '') throw new Error('Invalid Community Format'); + const user: User = { + username: username, + firstName: firstName, + lastName: lastName, + tags: tags, + community: community, + status: status, + }; + return await UserModel.create(user); +} + /** * Populates the database with predefined data. * Logs the status of the operation to the console. @@ -298,11 +315,14 @@ const populate = async () => { // const aiQuestions = await getQuestionsByTags(AI_TAGS); const cloudQuestions = await getQuestionsByTags([t5, t8]); - await communityCreate('front-end-development', FRONT_END_TAGS, [], frontEndQuestions); + const community1 = await communityCreate('front-end-development', FRONT_END_TAGS, [], frontEndQuestions); // await communityCreate('back-end-development', BACK_END_TAGS, [], backEndQuestions); // await communityCreate('machine learning', ML_TAGS, [], machineLearningQuestions); // await communityCreate('ai', AI_TAGS, [], aiQuestions); - await communityCreate('cloud computing', CLOUD_TAGS, [], cloudQuestions); + const community2 = await communityCreate('cloud computing', CLOUD_TAGS, [], cloudQuestions); + + await userCreate('user1', 'John', 'Doe', [t1, t2], community1, 'low'); + console.log('Database populated'); } catch (err) { diff --git a/server/types.ts b/server/types.ts index bd119b1..79cb97d 100644 --- a/server/types.ts +++ b/server/types.ts @@ -19,6 +19,18 @@ export interface Community { questions: Question[]; } +/** + * Interface representing User + */ +export interface User { + username: string; + firstName: string; + lastName: string; + tags: Tag[]; + community: Community; + status: string; +} + /** * Interface representing an Answer document, which contains: * - _id - The unique identifier for the answer. Optional field From ab659ef55876094bafe3cdf05ebd28f3196c68b5 Mon Sep 17 00:00:00 2001 From: Kristen Liu Date: Fri, 15 Nov 2024 17:36:24 -0500 Subject: [PATCH 06/16] fixed user model --- server/models/schema/user.ts | 6 ------ server/models/users.ts | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/server/models/schema/user.ts b/server/models/schema/user.ts index 8afe78e..257df51 100644 --- a/server/models/schema/user.ts +++ b/server/models/schema/user.ts @@ -12,27 +12,21 @@ const userSchema: Schema = new Schema( { username: { type: String, - required: true, }, firstName: { type: String, - required: true, }, lastName: { type: String, - required: true, }, tags: { type: [{ type: Schema.Types.ObjectId, ref: 'Tag' }], - required: true, }, community: { type: { type: Schema.Types.ObjectId, ref: 'Community' }, - required: true, }, status: { type: String, - required: true, }, }, { collection: 'User' }, diff --git a/server/models/users.ts b/server/models/users.ts index 4c39e6b..17ffc7a 100644 --- a/server/models/users.ts +++ b/server/models/users.ts @@ -1,7 +1,7 @@ // Community Document Schema import mongoose, { Model } from 'mongoose'; import { User } from '../types'; -import userSchema from './schema/community'; +import userSchema from './schema/user'; /** * Mongoose model for the `Community` collection. From 22aa0545587cae0211da0c23306b840ba90f4885 Mon Sep 17 00:00:00 2001 From: Kristen Liu Date: Sat, 16 Nov 2024 14:54:53 -0500 Subject: [PATCH 07/16] create user model w no init data --- server/populate_db.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/server/populate_db.ts b/server/populate_db.ts index ccf89b2..b69f231 100644 --- a/server/populate_db.ts +++ b/server/populate_db.ts @@ -217,18 +217,18 @@ async function communityCreate(name: string, tags: string[], users: string[], qu /** * FIX THIS COMMENT */ -async function userCreate(username: string, firstName: string, lastName: string, tags: Tag[], community: Community, status: string): Promise { - if (firstName === '' || lastName === '' || tags.length === 0 || status === '') throw new Error('Invalid Community Format'); - const user: User = { - username: username, - firstName: firstName, - lastName: lastName, - tags: tags, - community: community, - status: status, - }; - return await UserModel.create(user); -} +// async function userCreate(username: string, firstName: string, lastName: string, tags: Tag[], community: Community, status: string): Promise { +// if (firstName === '' || lastName === '' || tags.length === 0 || status === '') throw new Error('Invalid Community Format'); +// const user: User = { +// username: username, +// firstName: firstName, +// lastName: lastName, +// tags: tags, +// community: community, +// status: status, +// }; +// return await UserModel.create(user); +// } /** * Populates the database with predefined data. @@ -321,7 +321,7 @@ const populate = async () => { // await communityCreate('ai', AI_TAGS, [], aiQuestions); const community2 = await communityCreate('cloud computing', CLOUD_TAGS, [], cloudQuestions); - await userCreate('user1', 'John', 'Doe', [t1, t2], community1, 'low'); + // await userCreate('user1', 'John', 'Doe', [t1, t2], community1, 'low'); console.log('Database populated'); From 4b15f29c77eb7bd5a28a9ba6a70516cfa4580e68 Mon Sep 17 00:00:00 2001 From: g-pooja-03 Date: Sat, 16 Nov 2024 15:02:15 -0500 Subject: [PATCH 08/16] changes comitted --- server/models/schema/user.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/server/models/schema/user.ts b/server/models/schema/user.ts index 8afe78e..257df51 100644 --- a/server/models/schema/user.ts +++ b/server/models/schema/user.ts @@ -12,27 +12,21 @@ const userSchema: Schema = new Schema( { username: { type: String, - required: true, }, firstName: { type: String, - required: true, }, lastName: { type: String, - required: true, }, tags: { type: [{ type: Schema.Types.ObjectId, ref: 'Tag' }], - required: true, }, community: { type: { type: Schema.Types.ObjectId, ref: 'Community' }, - required: true, }, status: { type: String, - required: true, }, }, { collection: 'User' }, From e073248170319b1f4ff3a338491982c1b76a1d26 Mon Sep 17 00:00:00 2001 From: Kristen Liu Date: Sat, 16 Nov 2024 15:11:02 -0500 Subject: [PATCH 09/16] merged with main --- client/src/hooks/useCreateUser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/hooks/useCreateUser.ts b/client/src/hooks/useCreateUser.ts index 9b9db75..1f9b66f 100644 --- a/client/src/hooks/useCreateUser.ts +++ b/client/src/hooks/useCreateUser.ts @@ -2,7 +2,7 @@ import { ChangeEvent, useState } from 'react'; import { createUserWithEmailAndPassword } from 'firebase/auth'; import { useNavigate } from 'react-router-dom'; -import { doc, setDoc } from 'firebase/firestore'; +// import { doc, setDoc } from 'firebase/firestore'; import { auth, db } from '../firebaseConfig'; import useLoginContext from './useLoginContext'; From 616ace7f887ba2449d8e92d7797f82e29ee1627a Mon Sep 17 00:00:00 2001 From: g-pooja-03 Date: Sat, 16 Nov 2024 16:42:27 -0500 Subject: [PATCH 10/16] refactored users to go to store in mongo --- client/src/hooks/useCreateUser.ts | 20 +++++++++++++------- client/src/services/userService.ts | 25 +++++++++++++++++++++++++ client/src/types.ts | 2 +- server/controller/user.ts | 25 ++++++++++++++++++++++++- server/types.ts | 2 +- 5 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 client/src/services/userService.ts diff --git a/client/src/hooks/useCreateUser.ts b/client/src/hooks/useCreateUser.ts index 1f9b66f..a560812 100644 --- a/client/src/hooks/useCreateUser.ts +++ b/client/src/hooks/useCreateUser.ts @@ -2,9 +2,9 @@ import { ChangeEvent, useState } from 'react'; import { createUserWithEmailAndPassword } from 'firebase/auth'; import { useNavigate } from 'react-router-dom'; -// import { doc, setDoc } from 'firebase/firestore'; -import { auth, db } from '../firebaseConfig'; -import useLoginContext from './useLoginContext'; +import { auth } from '../firebaseConfig'; +import { User } from '../types'; +import addUser from '../services/userService'; /** * Custom hook to handle user creation input and submission. @@ -25,7 +25,7 @@ const useCreateUser = () => { const [errorMessage, setErrorMessage] = useState(''); const [isLoading, setIsLoading] = useState(false); - const { setUser } = useLoginContext(); + // const { setUser } = useLoginContext(); const navigate = useNavigate(); const handleEmailChange = (e: ChangeEvent) => { @@ -48,10 +48,16 @@ const useCreateUser = () => { event.preventDefault(); setIsLoading(true); try { - const { user } = await createUserWithEmailAndPassword(auth, email, password); + await createUserWithEmailAndPassword(auth, email, password); setIsLoading(false); - // setUser({ username: user.email ?? '', status: 'low' }); - // navigate('/home'); + const user: User = { + username: email, + firstName, + lastName, + tags: [], + status: 'low', + }; + await addUser(user); navigate('/new/tagselection'); } catch (error) { setErrorMessage((error as Error).message); diff --git a/client/src/services/userService.ts b/client/src/services/userService.ts new file mode 100644 index 0000000..48eb8c5 --- /dev/null +++ b/client/src/services/userService.ts @@ -0,0 +1,25 @@ +import { User } from '../types'; +import api from './config'; + +const USER_API_URL = `${process.env.REACT_APP_SERVER_URL}/user`; + +/** + * Adds a new user to the database. + * + * @param user - The user object containing the user's details. + * @throws Error Throws an error if the request fails or the response status is not 200. + * @returns The created user object from the server response. + */ +const addUser = async (user: User): Promise => { + try { + const res = await api.post(`${USER_API_URL}/add`, user); + if (res.status !== 200) { + throw new Error('Error while creating a new user'); + } + return res.data; + } catch (error) { + throw new Error(`Error while adding user: ${(error as Error).message}`); + } +}; + +export default addUser; diff --git a/client/src/types.ts b/client/src/types.ts index 3e1618e..2bc6317 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -10,7 +10,7 @@ export interface User { firstName: string; lastName: string; tags: Tag[]; - community: Community; + community?: Community; status: string; } diff --git a/server/controller/user.ts b/server/controller/user.ts index 137cc51..3d93e4d 100644 --- a/server/controller/user.ts +++ b/server/controller/user.ts @@ -1,9 +1,32 @@ +/* eslint-disable no-console */ import express, { Request, Response, Router } from 'express'; -import UserModel from '../models/communities'; +import UserModel from '../models/users'; const userController = () => { const router: Router = express.Router(); + /** + * Adds a new user to the database. + */ + router.post('/add', async (req: Request, res: Response) => { + try { + const { username, firstName, lastName, tags, status } = req.body; + + const newUser = await UserModel.create({ + username, + firstName, + lastName, + tags: tags || [], + status, + }); + + return res.status(200).json(newUser); + } catch (error) { + console.error('Error adding user:', error); + return res.status(500).json({ error: 'Internal server error' }); + } + }); + return router; }; diff --git a/server/types.ts b/server/types.ts index 79cb97d..e3bc190 100644 --- a/server/types.ts +++ b/server/types.ts @@ -27,7 +27,7 @@ export interface User { firstName: string; lastName: string; tags: Tag[]; - community: Community; + community?: Community; status: string; } From 67c963b1dfc80da85b4a911ee74a5f6abc4b625d Mon Sep 17 00:00:00 2001 From: g-pooja-03 Date: Sat, 16 Nov 2024 17:19:13 -0500 Subject: [PATCH 11/16] user, tags, and community save to mongo under User --- .../newUser/chooseCommunityPage/index.tsx | 23 +++------ .../login/newUser/chooseTagsPage/index.tsx | 17 +++---- client/src/hooks/useCreateUser.ts | 2 +- client/src/hooks/useLogin.ts | 5 +- client/src/services/userService.ts | 19 +++++++- client/src/types.ts | 4 +- server/controller/user.ts | 47 ++++++++++++++++++- server/models/schema/user.ts | 4 +- server/types.ts | 4 +- 9 files changed, 82 insertions(+), 43 deletions(-) diff --git a/client/src/components/login/newUser/chooseCommunityPage/index.tsx b/client/src/components/login/newUser/chooseCommunityPage/index.tsx index 2c946ff..2ca4013 100644 --- a/client/src/components/login/newUser/chooseCommunityPage/index.tsx +++ b/client/src/components/login/newUser/chooseCommunityPage/index.tsx @@ -2,8 +2,8 @@ import React, { useState } from 'react'; import './index.css'; import { NavLink } from 'react-router-dom'; -import { doc, setDoc } from 'firebase/firestore'; -import { db, auth } from '../../../../firebaseConfig'; +import { auth } from '../../../../firebaseConfig'; +import { updateUserCommunity } from '../../../../services/userService'; import logo from '../../../../logo.svg'; import useCommunityNames from '../../../../hooks/useCommunityNames'; @@ -22,22 +22,11 @@ const ChooseCommunityPage = () => { try { const user = auth.currentUser; if (user) { - console.log(user.email); - if (user.email) { - const userRef = doc(db, 'users', user.email); - await setDoc( - userRef, - { - username: user.email, - community, - }, - { merge: true }, - ); - } else { - console.error('Error saving community'); - } + console.log('Saving community for user:', user.email); + await updateUserCommunity(user.email!, community); // Call the backend service + console.log('Community updated successfully'); } else { - console.error('Error saving community'); + console.error('No user is logged in.'); } } catch (error) { console.error('Error saving community:', error); diff --git a/client/src/components/login/newUser/chooseTagsPage/index.tsx b/client/src/components/login/newUser/chooseTagsPage/index.tsx index 5f5d3f3..0f9fc71 100644 --- a/client/src/components/login/newUser/chooseTagsPage/index.tsx +++ b/client/src/components/login/newUser/chooseTagsPage/index.tsx @@ -2,10 +2,9 @@ import React, { useState } from 'react'; import './index.css'; import { NavLink } from 'react-router-dom'; -import { doc, updateDoc } from 'firebase/firestore'; -// eslint-disable-next-line import/no-extraneous-dependencies import useTagNames from '../../../../hooks/useTagNames'; -import { db, auth } from '../../../../firebaseConfig'; +import { auth } from '../../../../firebaseConfig'; +import { updateUserTags } from '../../../../services/userService'; // Import the userService function import logo from '../../../../logo.svg'; /** @@ -29,15 +28,11 @@ const ChooseTagsPage = () => { try { const user = auth.currentUser; if (user) { - console.log(user.email); - if (user.email) { - const userRef = doc(db, 'users', user.email); - await updateDoc(userRef, { tags }); - } else { - console.error('Error saving tags'); - } + console.log('Saving tags for user:', user.email); + await updateUserTags(user.email!, tags); + console.log('Tags updated successfully'); } else { - console.error('Error saving tags'); + console.error('No user is logged in.'); } } catch (error) { console.error('Error saving tags:', error); diff --git a/client/src/hooks/useCreateUser.ts b/client/src/hooks/useCreateUser.ts index a560812..78d1fc8 100644 --- a/client/src/hooks/useCreateUser.ts +++ b/client/src/hooks/useCreateUser.ts @@ -4,7 +4,7 @@ import { createUserWithEmailAndPassword } from 'firebase/auth'; import { useNavigate } from 'react-router-dom'; import { auth } from '../firebaseConfig'; import { User } from '../types'; -import addUser from '../services/userService'; +import { addUser } from '../services/userService'; /** * Custom hook to handle user creation input and submission. diff --git a/client/src/hooks/useLogin.ts b/client/src/hooks/useLogin.ts index 3f184a7..8df2e06 100644 --- a/client/src/hooks/useLogin.ts +++ b/client/src/hooks/useLogin.ts @@ -2,7 +2,6 @@ import { useNavigate } from 'react-router-dom'; import { ChangeEvent, useState } from 'react'; import { signInWithEmailAndPassword } from 'firebase/auth'; -import useLoginContext from './useLoginContext'; import { auth } from '../firebaseConfig'; /** @@ -20,7 +19,6 @@ const useLogin = () => { const [password, setPassword] = useState(''); const [errorMessage, setErrorMessage] = useState(''); - const { setUser } = useLoginContext(); const navigate = useNavigate(); /** @@ -44,8 +42,7 @@ const useLogin = () => { const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); try { - const { user } = await signInWithEmailAndPassword(auth, email, password); - // setUser({ username: user.email ?? '', status: 'low' }); + await signInWithEmailAndPassword(auth, email, password); navigate('/home'); } catch (error) { setErrorMessage((error as Error).message); diff --git a/client/src/services/userService.ts b/client/src/services/userService.ts index 48eb8c5..1a1ebef 100644 --- a/client/src/services/userService.ts +++ b/client/src/services/userService.ts @@ -1,4 +1,4 @@ -import { User } from '../types'; +import { Tag, User } from '../types'; import api from './config'; const USER_API_URL = `${process.env.REACT_APP_SERVER_URL}/user`; @@ -22,4 +22,19 @@ const addUser = async (user: User): Promise => { } }; -export default addUser; +const updateUserTags = async (username: string, tags: string[]): Promise => { + const res = await api.put(`${USER_API_URL}/updateTags`, { username, tags }); + if (res.status !== 200) { + throw new Error('Failed to update user tags'); + } + return res.data; +}; +const updateUserCommunity = async (username: string, community: string): Promise => { + const res = await api.put(`${USER_API_URL}/updateCommunity`, { username, community }); + if (res.status !== 200) { + throw new Error('Failed to update user community'); + } + return res.data; +}; + +export { addUser, updateUserTags, updateUserCommunity }; diff --git a/client/src/types.ts b/client/src/types.ts index 2bc6317..40719a6 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -9,8 +9,8 @@ export interface User { username: string; firstName: string; lastName: string; - tags: Tag[]; - community?: Community; + tags: string[]; + community?: string; status: string; } diff --git a/server/controller/user.ts b/server/controller/user.ts index 3d93e4d..ad29836 100644 --- a/server/controller/user.ts +++ b/server/controller/user.ts @@ -22,8 +22,51 @@ const userController = () => { return res.status(200).json(newUser); } catch (error) { - console.error('Error adding user:', error); - return res.status(500).json({ error: 'Internal server error' }); + return res.status(500).json({ error: 'Error adding user' }); + } + }); + + router.put('/updateTags', async (req: Request, res: Response) => { + try { + const { username, tags } = req.body; + + if (!username || !tags) { + return res.status(400).json({ error: 'Username and tags are required' }); + } + + const updatedUser = await UserModel.findOneAndUpdate( + { username }, + { $set: { tags } }, + { new: true }, + ); + + if (!updatedUser) { + return res.status(404).json({ error: 'User not found' }); + } + + return res.status(200).json(updatedUser); + } catch (error) { + return res.status(500).json({ error: 'Error updating tags' }); + } + }); + + router.put('/updateCommunity', async (req: Request, res: Response) => { + try { + const { username, community } = req.body; + + if (!username || !community) { + return res.status(400).json({ message: 'Username and community are required' }); + } + + const user = await UserModel.findOneAndUpdate({ username }, { community }, { new: true }); + + if (!user) { + return res.status(404).json({ message: 'User not found' }); + } + + return res.status(200).json(user); + } catch (error) { + return res.status(500).json({ message: 'Error updating community' }); } }); diff --git a/server/models/schema/user.ts b/server/models/schema/user.ts index 257df51..7ca5849 100644 --- a/server/models/schema/user.ts +++ b/server/models/schema/user.ts @@ -20,10 +20,10 @@ const userSchema: Schema = new Schema( type: String, }, tags: { - type: [{ type: Schema.Types.ObjectId, ref: 'Tag' }], + type: [String], }, community: { - type: { type: Schema.Types.ObjectId, ref: 'Community' }, + type: String, }, status: { type: String, diff --git a/server/types.ts b/server/types.ts index e3bc190..58be6b3 100644 --- a/server/types.ts +++ b/server/types.ts @@ -26,8 +26,8 @@ export interface User { username: string; firstName: string; lastName: string; - tags: Tag[]; - community?: Community; + tags: string[]; + community?: string; status: string; } From deedd8988b0f45b4b08545583f8a4a6985c64c2b Mon Sep 17 00:00:00 2001 From: g-pooja-03 Date: Sat, 16 Nov 2024 17:32:37 -0500 Subject: [PATCH 12/16] should pull from mongo for data as well --- .../main/profile/accountInfo/index.tsx | 29 +++++++------------ .../components/main/profile/tags/index.tsx | 26 ++++++----------- client/src/services/userService.ts | 10 ++++++- server/controller/user.ts | 20 +++++++++++++ 4 files changed, 49 insertions(+), 36 deletions(-) diff --git a/client/src/components/main/profile/accountInfo/index.tsx b/client/src/components/main/profile/accountInfo/index.tsx index 824b0e6..5bdd23b 100644 --- a/client/src/components/main/profile/accountInfo/index.tsx +++ b/client/src/components/main/profile/accountInfo/index.tsx @@ -2,13 +2,12 @@ /* eslint-disable no-console */ import React, { useEffect, useState } from 'react'; import './index.css'; -import { doc, getDoc } from 'firebase/firestore'; import { NavLink } from 'react-router-dom'; -import { auth, db } from '../../../../firebaseConfig'; -import useUserContext from '../../../../hooks/useUserContext'; +import { auth } from '../../../../firebaseConfig'; +import { getUser } from '../../../../services/userService'; /** - * AccountInfo component which displays the user's username and password. + * AccountInfo component which displays the user's username and status. */ const AccountInfo = () => { const [userData, setUserData] = useState({ @@ -18,25 +17,19 @@ const AccountInfo = () => { status: '', }); const [creationTime, setCreationTime] = useState(null); - const { user } = useUserContext(); + useEffect(() => { const fetchUserData = async () => { const firebaseUser = auth.currentUser; if (firebaseUser && firebaseUser.email) { try { - const userRef = doc(db, 'users', firebaseUser.email); - const userDoc = await getDoc(userRef); - if (userDoc.exists()) { - const data = userDoc.data(); - setUserData({ - first_name: data.first_name || '', - last_name: data.last_name || '', - username: data.username || firebaseUser.email, - status: user.status || 'low', - }); - } else { - console.log('No such user!'); - } + const data = await getUser(firebaseUser.email); + setUserData({ + first_name: data.firstName, + last_name: data.lastName, + username: data.username, + status: data.status, + }); } catch (error) { console.error('Error fetching user data:', error); } diff --git a/client/src/components/main/profile/tags/index.tsx b/client/src/components/main/profile/tags/index.tsx index fb01680..07a5e7a 100644 --- a/client/src/components/main/profile/tags/index.tsx +++ b/client/src/components/main/profile/tags/index.tsx @@ -1,10 +1,9 @@ /* eslint-disable no-console */ import React, { useEffect, useState } from 'react'; -import { collection, getDocs, query, where, doc, updateDoc } from 'firebase/firestore'; import useUserContext from '../../../../hooks/useUserContext'; import useTagNames from '../../../../hooks/useTagNames'; -import { db } from '../../../../firebaseConfig'; import './index.css'; +import { updateUserTags, getUser } from '../../../../services/userService'; /** * TagsInfo component which displays and allows the user to manage their chosen tags. @@ -15,21 +14,14 @@ const TagsInfo = () => { const [chosenTags, setChosenTags] = useState([]); const [searchTerm, setSearchTerm] = useState(''); + // Fetch tags from MongoDB when the component is mounted useEffect(() => { const fetchTags = async () => { if (!user?.username) return; try { - const q = query(collection(db, 'users'), where('username', '==', user.username)); - const querySnapshot = await getDocs(q); - - if (!querySnapshot.empty) { - const userDoc = querySnapshot.docs[0]; - const userData = userDoc.data(); - setChosenTags(userData.tags || []); - } else { - console.log('User not found'); - } + const data = await getUser(user.username); // Fetch user data from MongoDB + setChosenTags(data.tags || []); } catch (error) { console.error('Error fetching tags:', error); } @@ -38,10 +30,12 @@ const TagsInfo = () => { fetchTags(); }, [user]); + // Handle adding a tag to the chosen list const handleTagAdd = (tagName: string) => { setChosenTags(prevTags => [...prevTags, tagName]); }; + // Handle removing a tag from the chosen list const handleTagRemove = (tagName: string) => { setChosenTags(prevTags => prevTags.filter(tag => tag !== tagName)); }; @@ -50,8 +44,7 @@ const TagsInfo = () => { if (!user?.username) return; try { - const userDocRef = doc(db, 'users', user.username); - await updateDoc(userDocRef, { tags: chosenTags }); + await updateUserTags(user.username, chosenTags); console.log('Tags updated:', chosenTags); } catch (error) { console.error('Error saving tags:', error); @@ -59,9 +52,8 @@ const TagsInfo = () => { }; const filteredTags = tagNames - .filter(tag => !chosenTags.includes(tag.name)) // Only show tags not already chosen - .filter(tag => tag.name.toLowerCase().includes(searchTerm.toLowerCase())); // Apply search filter - + .filter(tag => !chosenTags.includes(tag.name)) + .filter(tag => tag.name.toLowerCase().includes(searchTerm.toLowerCase())); return (
    diff --git a/client/src/services/userService.ts b/client/src/services/userService.ts index 1a1ebef..9fbfb53 100644 --- a/client/src/services/userService.ts +++ b/client/src/services/userService.ts @@ -37,4 +37,12 @@ const updateUserCommunity = async (username: string, community: string): Promise return res.data; }; -export { addUser, updateUserTags, updateUserCommunity }; +const getUser = async (username: string): Promise => { + const res = await api.get(`${USER_API_URL}/getUser`, { params: { username } }); + if (res.status !== 200) { + throw new Error('Failed to fetch user data'); + } + return res.data; +}; + +export { addUser, updateUserTags, updateUserCommunity, getUser }; diff --git a/server/controller/user.ts b/server/controller/user.ts index ad29836..c152979 100644 --- a/server/controller/user.ts +++ b/server/controller/user.ts @@ -70,6 +70,26 @@ const userController = () => { } }); + router.get('/getUser', async (req: Request, res: Response) => { + try { + const { username } = req.query; + + if (!username) { + return res.status(400).json({ message: 'Username is required' }); + } + + const user = await UserModel.findOne({ username }); + + if (!user) { + return res.status(404).json({ message: 'User not found' }); + } + + return res.status(200).json(user); + } catch (error) { + return res.status(500).json({ message: 'Error fetching user data' }); + } + }); + return router; }; From ceb55eec87e1326ab703f66a3667c4b48de0a0d8 Mon Sep 17 00:00:00 2001 From: g-pooja-03 Date: Sat, 16 Nov 2024 17:56:54 -0500 Subject: [PATCH 13/16] routing fixes --- client/src/components/fakestackoverflow.tsx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/client/src/components/fakestackoverflow.tsx b/client/src/components/fakestackoverflow.tsx index a71d251..d707239 100644 --- a/client/src/components/fakestackoverflow.tsx +++ b/client/src/components/fakestackoverflow.tsx @@ -17,9 +17,8 @@ import AccountInfo from './main/profile/accountInfo'; import TagsInfo from './main/profile/tags'; import CommunityInfo from './main/profile/community'; import ChooseTagsPage from './login/newUser/chooseTagsPage/index'; -import CommunityHomePage from './main/homePage/community'; -// import PostLoginCommunity from './login/newUser/chooseCommunityPage'; import ChooseCommunityPage from './login/newUser/chooseCommunityPage'; +import CommunityHomePage from './main/homePage/community'; const ProtectedRoute = ({ user, @@ -52,11 +51,8 @@ const FakeStackOverflow = ({ socket }: { socket: FakeSOSocket | null }) => { } /> } /> } /> - } - element={} - /> + } /> + {/* Protected Routes */} { { }> } /> } /> - } /> + {/* } /> */} } From 7a829ff8ff332ad30e98439e3e6b51bb95b9d537 Mon Sep 17 00:00:00 2001 From: g-pooja-03 Date: Sat, 16 Nov 2024 18:09:26 -0500 Subject: [PATCH 14/16] fixing routing and information pull --- client/src/hooks/useCreateUser.ts | 4 +++- client/src/hooks/useLogin.ts | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/client/src/hooks/useCreateUser.ts b/client/src/hooks/useCreateUser.ts index 78d1fc8..cdf9b19 100644 --- a/client/src/hooks/useCreateUser.ts +++ b/client/src/hooks/useCreateUser.ts @@ -5,6 +5,7 @@ import { useNavigate } from 'react-router-dom'; import { auth } from '../firebaseConfig'; import { User } from '../types'; import { addUser } from '../services/userService'; +import useLoginContext from './useLoginContext'; /** * Custom hook to handle user creation input and submission. @@ -25,7 +26,7 @@ const useCreateUser = () => { const [errorMessage, setErrorMessage] = useState(''); const [isLoading, setIsLoading] = useState(false); - // const { setUser } = useLoginContext(); + const { setUser } = useLoginContext(); const navigate = useNavigate(); const handleEmailChange = (e: ChangeEvent) => { @@ -57,6 +58,7 @@ const useCreateUser = () => { tags: [], status: 'low', }; + setUser(user); await addUser(user); navigate('/new/tagselection'); } catch (error) { diff --git a/client/src/hooks/useLogin.ts b/client/src/hooks/useLogin.ts index 8df2e06..88874de 100644 --- a/client/src/hooks/useLogin.ts +++ b/client/src/hooks/useLogin.ts @@ -1,8 +1,9 @@ -/* eslint-disable import/no-extraneous-dependencies */ import { useNavigate } from 'react-router-dom'; import { ChangeEvent, useState } from 'react'; import { signInWithEmailAndPassword } from 'firebase/auth'; import { auth } from '../firebaseConfig'; +import useLoginContext from './useLoginContext'; +import { getUser } from '../services/userService'; /** * Custom hook to handle login input and submission. @@ -18,7 +19,7 @@ const useLogin = () => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [errorMessage, setErrorMessage] = useState(''); - + const { setUser } = useLoginContext(); const navigate = useNavigate(); /** @@ -43,6 +44,15 @@ const useLogin = () => { event.preventDefault(); try { await signInWithEmailAndPassword(auth, email, password); + const userData = await getUser(email); + setUser({ + username: userData.username, + firstName: userData.firstName, + lastName: userData.lastName, + tags: userData.tags, + status: userData.status, + }); + navigate('/home'); } catch (error) { setErrorMessage((error as Error).message); From 8068681b14250abb73d08f180b04decfbdecb627 Mon Sep 17 00:00:00 2001 From: g-pooja-03 Date: Mon, 18 Nov 2024 13:49:38 -0500 Subject: [PATCH 15/16] status restricted values --- client/src/types.ts | 2 +- server/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/types.ts b/client/src/types.ts index 40719a6..8a50bbc 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -11,7 +11,7 @@ export interface User { lastName: string; tags: string[]; community?: string; - status: string; + status: 'low' | 'high'; } /** diff --git a/server/types.ts b/server/types.ts index 58be6b3..b0cc2a3 100644 --- a/server/types.ts +++ b/server/types.ts @@ -28,7 +28,7 @@ export interface User { lastName: string; tags: string[]; community?: string; - status: string; + status: 'low' | 'high'; } /** From 99a1f979f890a951ae9e56ef1376a7052c15fb98 Mon Sep 17 00:00:00 2001 From: g-pooja-03 Date: Mon, 18 Nov 2024 15:05:13 -0500 Subject: [PATCH 16/16] user definition update --- client/src/hooks/useCreateUser.ts | 1 + client/src/hooks/useLogin.ts | 1 + client/src/types.ts | 2 +- server/controller/user.ts | 3 ++- server/types.ts | 2 +- 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/client/src/hooks/useCreateUser.ts b/client/src/hooks/useCreateUser.ts index cdf9b19..0b7e6f9 100644 --- a/client/src/hooks/useCreateUser.ts +++ b/client/src/hooks/useCreateUser.ts @@ -56,6 +56,7 @@ const useCreateUser = () => { firstName, lastName, tags: [], + community: '', status: 'low', }; setUser(user); diff --git a/client/src/hooks/useLogin.ts b/client/src/hooks/useLogin.ts index 88874de..1a37881 100644 --- a/client/src/hooks/useLogin.ts +++ b/client/src/hooks/useLogin.ts @@ -50,6 +50,7 @@ const useLogin = () => { firstName: userData.firstName, lastName: userData.lastName, tags: userData.tags, + community: userData.community, status: userData.status, }); diff --git a/client/src/types.ts b/client/src/types.ts index 8a50bbc..e699339 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -10,7 +10,7 @@ export interface User { firstName: string; lastName: string; tags: string[]; - community?: string; + community: string; status: 'low' | 'high'; } diff --git a/server/controller/user.ts b/server/controller/user.ts index c152979..518a848 100644 --- a/server/controller/user.ts +++ b/server/controller/user.ts @@ -10,13 +10,14 @@ const userController = () => { */ router.post('/add', async (req: Request, res: Response) => { try { - const { username, firstName, lastName, tags, status } = req.body; + const { username, firstName, lastName, tags, community, status } = req.body; const newUser = await UserModel.create({ username, firstName, lastName, tags: tags || [], + community: community || '', status, }); diff --git a/server/types.ts b/server/types.ts index b0cc2a3..84edde6 100644 --- a/server/types.ts +++ b/server/types.ts @@ -27,7 +27,7 @@ export interface User { firstName: string; lastName: string; tags: string[]; - community?: string; + community: string; status: 'low' | 'high'; }