Skip to content
Open
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: 2 additions & 0 deletions client/src/components/fakestackoverflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import UsersListPage from './main/usersListPage';
import ProfileSettings from './profileSettings';
import AllGamesPage from './main/games/allGamesPage';
import GamePage from './main/games/gamePage';
import AllCommunitiesPage from './main/communities/allCommunitiesPage';

const ProtectedRoute = ({
user,
Expand Down Expand Up @@ -66,6 +67,7 @@ const FakeStackOverflow = ({ socket }: { socket: FakeSOSocket | null }) => {
<Route path='/user/:username' element={<ProfileSettings />} />
<Route path='/games' element={<AllGamesPage />} />
<Route path='/games/:gameID' element={<GamePage />} />
<Route path='/communities' element={<AllCommunitiesPage />} />
</Route>
}
</Routes>
Expand Down
79 changes: 79 additions & 0 deletions client/src/components/main/communities/addCommunityForm/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
.add-community-form {
background: #ffffff;
border: 1px solid #e0e0e0;
padding: 20px;
border-radius: 12px;
max-width: 400px;
margin: 20px auto;
}

.add-community-form h2 {
font-size: 1.5rem;
margin-bottom: 1rem;
text-align: center;
}

.add-community-form label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
}

.add-community-form input,
.add-community-form textarea {
width: 100%;
padding: 8px 10px;
margin-bottom: 1rem;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 1rem;
}

.add-community-form textarea {
resize: vertical;
min-height: 80px;
}

.add-community-form .form-actions {
display: flex;
justify-content: space-between;
gap: 10px;
}

.add-community-form button {
flex: 1;
padding: 10px;
border: none;
border-radius: 8px;
font-size: 1rem;
cursor: pointer;
}

.add-community-form .visibility-checkbox {
display: flex;
align-items: center;
gap: 10px;
}

.add-community-form .visibility-checkbox label {
margin-bottom: 0;
font-weight: normal;
display: flex;
align-items: center;
}


.add-community-form button.submit {
background-color: #4caf50 !important;
color: white !important;
}

.add-community-form button.cancel {
background-color: #f44336 !important;
color: white !important;
}

.add-community-form button:hover {
opacity: 0.9;
}

85 changes: 85 additions & 0 deletions client/src/components/main/communities/addCommunityForm/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React, { useState } from 'react';
import './index.css';

interface AddCommunityFormProps {
onSubmit: (data: { name: string; description: string; visibility: 'public' | 'private' }) => void;
onCancel: () => void;
errorMessage: string;
setErrorMessage: React.Dispatch<React.SetStateAction<string>>;
}

const AddCommunityForm: React.FC<AddCommunityFormProps> = ({
onSubmit,
onCancel,
errorMessage,
setErrorMessage,
}) => {
const [formData, setFormData] = useState({
name: '',
description: '',
visibility: 'public' as 'public' | 'private',
});

const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};

const handleCheckboxChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFormData(prev => ({
...prev,
visibility: e.target.checked ? 'private' : 'public',
}));
};

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();

if (errorMessage) {
setErrorMessage('');
}

onSubmit(formData);
setFormData({ name: '', description: '', visibility: 'public' });
};
return (
<form onSubmit={handleSubmit} className='add-community-form'>
<input
type='text'
name='name'
placeholder='Community Name'
value={formData.name}
onChange={handleChange}
required
/>
{errorMessage && <div style={{ color: 'red', marginTop: '5px' }}>{errorMessage}</div>}
<textarea
name='description'
placeholder='Description'
value={formData.description}
onChange={handleChange}
/>
<div className='visibility-checkbox'>
<label>
<input
type='checkbox'
checked={formData.visibility === 'private'}
onChange={handleCheckboxChange}
/>
Private Community
</label>
</div>

<div className='form-actions'>
<button type='submit' className='submit'>
Create
</button>
<button type='button' className='cancel' onClick={onCancel}>
Cancel
</button>
</div>
</form>
);
};

export default AddCommunityForm;
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* styling for all communities page */

.all-communities-container {
padding: 20px;
}

.space_between {
display: flex;
justify-content: space-between;
align-items: center;
}

.right_padding {
padding-right: 20px;
}

.bold_title {
font-weight: bold;
font-size: 24px;
}

.create-community-button {
position: absolute;
top: 20px;
right: 20px;
}

.create-community-button button {
background-color: #4caf50;
color: white;
padding: 10px 16px;
font-size: 16px;
border: none;
border-radius: 8px;
cursor: pointer;
}

.create-community-button button:hover {
background-color: #45a049;
}


.community-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
}

.community-card {
border: 1px solid #ccc; /* Add a border for debugging */
padding: 20px;
background-color: white;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React, { useState } from 'react';
import './index.css';
import useAllCommunitiesPage from '../../../../hooks/communities/useAllCommunitiesPage';
import AddCommunityForm from '../addCommunityForm';
import useUserContext from '../../../../hooks/useUserContext';
import CommunityView from '../communityView';

/**
* Represents the CommunityPage component which displays a list of communities
* and provides functionality to handle community clicks and ask a new question.
*/
const AllCommunitiesPage = () => {
const {
communities,
handleCommunityClick,
handleJoin,
handleAddCommunity,
errorMessage,
setErrorMessage,
} = useAllCommunitiesPage();
const [showForm, setShowForm] = useState(false);
const { user } = useUserContext();

return (
<div className='all-communities-container' style={{ position: 'relative' }}>
<div className='space_between right_padding'>
<div className='bold_title'>All Communities</div>
</div>
{/* button for form */}
<div className='create-community-button'>
{/* <button onClick={() => setShowForm(prev => !prev)}>
{showForm ? 'Cancel' : 'Create Community'}
</button> */}
<button onClick={() => setShowForm(true)}>Create Community</button>
</div>
{/* render form */}
{showForm && (
<AddCommunityForm
onSubmit={data => {
handleAddCommunity({
name: data.name,
description: data.description,
visibility: 'public',
members: [],
moderators: [],
owner: user?.username || 'unknown',
memberRequests: [],
questions: [],
});
setShowForm(false);
}}
onCancel={() => setShowForm(false)}
errorMessage={errorMessage}
setErrorMessage={setErrorMessage}
/>
)}
{/* community grid */}
<div className='community-grid'>
{communities.length === 0 ? (
<p>No communities available.</p>
) : (
communities.map(community => (
<CommunityView
key={community._id.toString()}
c={community}
clickCommunity={handleCommunityClick}
handleJoin={handleJoin}
/>
))
)}
</div>
</div>
);
};

export default AllCommunitiesPage;
51 changes: 51 additions & 0 deletions client/src/components/main/communities/communityView/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* styling for community view page */

.community-card {
background: #fff;
padding: 20px;
border: 1px solid #ddd;
border-radius: 10px;
transition: transform 0.2s ease, box-shadow 0.2s ease;
cursor: pointer;
}

.community-card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.community-name {
font-size: 20px;
font-weight: bold;
margin-bottom: 10px;
}

.community-description {
font-size: 14px;
color: #555;
margin-bottom: 15px;
}

.community-meta {
display: flex;
justify-content: space-between;
align-items: center;
}

.community-meta button {
padding: 6px 12px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
}

.community-meta button:hover {
background-color: #0056b3;
}

.community-meta .icon {
font-size: 18px;
}

Loading
Loading