Skip to content

Commit bf7e94b

Browse files
Merge pull request #3241 from OneCommunityGlobal/vaibhavi_CommunityPortal_faqSection
Saurabh taking over Shreya P - Phase 3 Creating frontend for activity FAQ section
2 parents 2bfae61 + d13e360 commit bf7e94b

4 files changed

Lines changed: 14642 additions & 14318 deletions

File tree

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import { useState } from 'react';
2+
import { useSelector } from 'react-redux';
3+
import styles from './FaqSection.module.css';
4+
5+
function FaqSection() {
6+
const faqs = [
7+
{
8+
id: 1,
9+
question: 'What is One Community?',
10+
answer:
11+
'One Community is a global nonprofit organization focused on creating sustainable living models and open-source solutions for a better world.',
12+
category: 'General',
13+
},
14+
{
15+
id: 2,
16+
question: 'How can I participate?',
17+
answer:
18+
'You can participate by volunteering, donating, or joining our collaborative projects in various fields like engineering, design, and education.',
19+
category: 'Participation',
20+
},
21+
{
22+
id: 3,
23+
question: 'Is One Community free to join?',
24+
answer:
25+
'Yes, joining One Community is completely free. We welcome anyone interested in sustainability and positive global change.',
26+
category: 'General',
27+
},
28+
{
29+
id: 4,
30+
question: 'How can I contact One Community?',
31+
answer:
32+
"You can contact us by clicking on the 'Contact Us' link below. Our team will respond as soon as possible.",
33+
category: 'Other',
34+
},
35+
{
36+
id: 5,
37+
question: 'What kind of events does One Community organize?',
38+
answer:
39+
'We organize workshops, webinars, sustainability summits, and community-building events throughout the year.',
40+
category: 'Events',
41+
},
42+
{
43+
id: 6,
44+
question: 'Where is One Community located?',
45+
answer:
46+
'One Community is a virtual and physical initiative with a developing sustainable village model in the United States.',
47+
category: 'Other',
48+
},
49+
];
50+
51+
const [openIndex, setOpenIndex] = useState(null);
52+
const [copied, setCopied] = useState(false);
53+
const [selectedCategory, setSelectedCategory] = useState('All');
54+
const [searchTerm, setSearchTerm] = useState('');
55+
const darkMode = useSelector(state => state.theme.darkMode);
56+
57+
const toggleFaq = id => {
58+
setOpenIndex(openIndex === id ? null : id);
59+
};
60+
61+
const handleContactClick = () => {
62+
const email = 'onecommunityglobal@gmail.com';
63+
navigator.clipboard
64+
.writeText(email)
65+
.then(() => setCopied(true))
66+
// eslint-disable-next-line no-console
67+
.catch(err => console.error('Failed to copy:', err));
68+
69+
setTimeout(() => setCopied(false), 2000);
70+
};
71+
72+
const handleCategoryClick = category => {
73+
setSelectedCategory(category);
74+
setOpenIndex(null);
75+
};
76+
77+
const handleSearchChange = e => {
78+
setSearchTerm(e.target.value);
79+
setOpenIndex(null);
80+
};
81+
82+
const filteredFaqs = faqs.filter(faq => {
83+
const matchesCategory = selectedCategory === 'All' || faq.category === selectedCategory;
84+
const matchesSearch =
85+
searchTerm === '' ||
86+
faq.question.toLowerCase().includes(searchTerm.toLowerCase()) ||
87+
faq.answer.toLowerCase().includes(searchTerm.toLowerCase());
88+
89+
return matchesCategory && matchesSearch;
90+
});
91+
92+
return (
93+
<div className={styles.faqContainer}>
94+
<h2 className={styles.faqTitle}>Frequently Asked Questions</h2>
95+
<p className={styles.faqSubtitle}>
96+
These are the most frequently asked questions about One Community.
97+
</p>
98+
99+
<input
100+
type="text"
101+
className={`${styles.faqSearch} ${darkMode ? styles.faqSearchDark : ''}`}
102+
placeholder="Search FAQs..."
103+
value={searchTerm}
104+
onChange={handleSearchChange}
105+
/>
106+
107+
<div className={styles.faqButtons}>
108+
{['All', 'General', 'Events', 'Participation', 'Other'].map(category => (
109+
<button
110+
key={category}
111+
type="button"
112+
className={`${styles.faqCategory} ${
113+
selectedCategory === category ? styles.active : ''
114+
} ${darkMode ? styles.faqCategoryDark : ''}`}
115+
onClick={() => handleCategoryClick(category)}
116+
>
117+
{category}
118+
</button>
119+
))}
120+
</div>
121+
122+
<div className={styles.faqList}>
123+
{filteredFaqs.length === 0 ? (
124+
<div className={styles.noResults}>
125+
<p>No FAQs found matching your criteria.</p>
126+
</div>
127+
) : (
128+
filteredFaqs.map(faq => (
129+
<div key={faq.id} className={styles.faqItem}>
130+
<button
131+
type="button"
132+
className={`${styles.faqQuestion} ${darkMode ? styles.faqQuestionDark : ''}`}
133+
onClick={() => toggleFaq(faq.id)}
134+
aria-expanded={openIndex === faq.id}
135+
>
136+
{faq.question}
137+
<span className={`${styles.faqArrow} ${openIndex === faq.id ? styles.open : ''}`}>
138+
&#9662;
139+
</span>
140+
</button>
141+
<div className={`${styles.faqAnswer} ${openIndex === faq.id ? styles.open : ''}`}>
142+
<div>{faq.answer}</div>
143+
</div>
144+
</div>
145+
))
146+
)}
147+
</div>
148+
149+
<p className={styles.faqContact}>
150+
Still have questions? Feel free to{' '}
151+
<button type="button" className={styles.contactLink} onClick={handleContactClick}>
152+
contact us
153+
</button>
154+
.{copied && <span className={styles.copiedMessage}> Copied!</span>}
155+
</p>
156+
</div>
157+
);
158+
}
159+
160+
export default FaqSection;
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
.faqContainer {
2+
width: 80%;
3+
margin: 0 auto;
4+
text-align: center;
5+
padding: 2rem 0;
6+
}
7+
8+
.faqTitle {
9+
font-size: 1.8rem;
10+
font-weight: bold;
11+
}
12+
13+
.faqSubtitle {
14+
font-size: 0.9rem;
15+
color: gray;
16+
margin-bottom: 1rem;
17+
}
18+
19+
.faqSearch {
20+
width: 60%;
21+
padding: 0.5rem;
22+
margin-bottom: 1rem;
23+
border: 1px solid #ccc;
24+
border-radius: 5px;
25+
text-align: center;
26+
}
27+
28+
.faqButtons {
29+
display: flex;
30+
justify-content: center;
31+
gap: 1rem;
32+
margin-bottom: 2rem;
33+
}
34+
35+
.faqCategory {
36+
padding: 0.6rem 1.2rem;
37+
border-radius: 20px;
38+
border: none;
39+
background-color: #f0f0f0;
40+
cursor: pointer;
41+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
42+
transform: translateY(0);
43+
}
44+
45+
.faqCategory:hover,
46+
.faqCategory.active {
47+
background-color: black;
48+
color: white;
49+
transform: translateY(-1px);
50+
}
51+
52+
.faqList {
53+
text-align: left;
54+
margin: 0 auto;
55+
width: 60%;
56+
}
57+
58+
.faqItem {
59+
margin-bottom: 1rem;
60+
border-bottom: 1px solid #ccc;
61+
padding-bottom: 0.5rem;
62+
}
63+
64+
.faqQuestion {
65+
font-weight: bold;
66+
cursor: pointer;
67+
display: flex;
68+
justify-content: space-between;
69+
align-items: center;
70+
background: none;
71+
border: none;
72+
width: 100%;
73+
text-align: left;
74+
}
75+
76+
.faqArrow {
77+
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
78+
}
79+
80+
.faqArrow.open {
81+
transform: rotate(180deg);
82+
}
83+
84+
.faqAnswer {
85+
margin-top: 0.5rem;
86+
font-size: 0.9rem;
87+
color: #333;
88+
display: grid;
89+
grid-template-rows: 0fr;
90+
transition: grid-template-rows 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
91+
opacity: 0;
92+
}
93+
94+
.faqAnswer.open {
95+
grid-template-rows: 1fr;
96+
opacity: 1;
97+
}
98+
99+
.faqAnswer > div {
100+
overflow: hidden;
101+
padding-top: 0.5rem;
102+
}
103+
104+
.faqContact {
105+
font-size: 0.9rem;
106+
margin-top: 2rem;
107+
}
108+
109+
.contactLink {
110+
color: blue;
111+
cursor: pointer;
112+
text-decoration: underline;
113+
background: none;
114+
border: none;
115+
padding: 0;
116+
font: inherit;
117+
}
118+
119+
.contactLink:hover {
120+
color: darkblue;
121+
}
122+
123+
.copiedMessage {
124+
color: green;
125+
}
126+
127+
.noResults {
128+
text-align: center;
129+
color: gray;
130+
}
131+
132+
.faqSearchDark {
133+
background-color: #2b3e59;
134+
color: #ffffff;
135+
border-color: #4a5a77;
136+
}
137+
138+
.faqSearchDark::placeholder {
139+
color: #8899aa;
140+
}
141+
142+
.faqCategoryDark {
143+
background-color: #2b3e59;
144+
color: #ffffff;
145+
border: 1px solid #4a5a77;
146+
}
147+
148+
.faqQuestionDark {
149+
color: #ffffff;
150+
}

src/routes.jsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ import TeamCard from './components/HGNHelpSkillsDashboard/TeamCard/TeamCard';
8686
import UserProfilePage from './components/HGNHelpSkillsDashboard/UserProfilePage';
8787

8888
import ActivityAgenda from './components/CommunityPortal/Activities/ActivityAgenda';
89-
import ActivityAttendance from './components/CommunityPortal/Activities/ActivityAttendance';
89+
9090
import ResourcesUsage from './components/CommunityPortal/Activities/activityId/ResourcesUsage';
9191
import EventNoShowChart from './components/CommunityPortal/Attendence/NoshowViz';
9292
import EventList from './components/CommunityPortal/Event/EventList/EventList';
@@ -108,7 +108,7 @@ import { JobAnalyticsCompetitiveRolesPage } from './components/Reports/JobAnalyt
108108

109109
import InjurySeverityChart from './components/BMDashboard/Injuries/InjurySeverityChart';
110110
import LBProtectedRoute from './components/common/LBDashboard/LBProtectedRoute/LBProtectedRoute';
111-
import Activity from './components/CommunityPortal/Activities/activityId/Activity';
111+
112112
import LBDashboard from './components/LBDashboard';
113113
import BiddingHomepage from './components/LBDashboard/BiddingHomepage/BiddingHomepage';
114114
import LBBidOverview from './components/LBDashboard/BiddingOverview/BiddingOverview';
@@ -146,12 +146,18 @@ import CreateNewTeam from './components/BMDashboard/Team/CreateNewTeam/CreateNew
146146

147147
import CPProtectedRoute from './components/common/CPDashboard/CPProtectedRoute';
148148
import CPDashboard from './components/CommunityPortal';
149-
import ActivityComments from './components/CommunityPortal/Activities/activityId/ActivityComments';
150149
import ActivityList from './components/CommunityPortal/Activities/ActivityList';
150+
import FaqSection from './components/CommunityPortal/Activities/FaqSection';
151+
import ActivityAttendance from './components/CommunityPortal/Activities/ActivityAttendance';
152+
import Activity from './components/CommunityPortal/Activities/activityId/Activity';
153+
import ActivityComments from './components/CommunityPortal/Activities/activityId/ActivityComments';
154+
151155
import Feedbackform from './components/CommunityPortal/Activities/Feedbackform';
156+
157+
import Register from './components/CommunityPortal/Activities/Register/Register';
158+
152159
import CPLogin from './components/CommunityPortal/Login';
153160
import ActivitiesPage from './components/CommunityPortal/Activities/ActivitiesPage';
154-
import Register from './components/CommunityPortal/Activities/Register/Register';
155161
import EventStats from './components/CommunityPortal/EventPersonalization/EventStats';
156162
import CommunityCalendar from './components/CommunityPortal/Calendar/CommunityCalendar';
157163
import PRGradingDashboard from './components/PRGradingDashboard/PRGradingDashboard';
@@ -967,9 +973,17 @@ export default (
967973

968974
<CPProtectedRoute path="/communityportal" exact component={CPDashboard} />
969975
<Route path="/communityportal/login" component={CPLogin} />
976+
<CPProtectedRoute
977+
path="/communityportal/activities/:activityid/faq"
978+
exact
979+
component={FaqSection}
980+
/>
981+
<CPProtectedRoute path="/communityportal/activities" exact component={ActivityList} />
982+
<CPProtectedRoute path="/communityportal/Activities" exact component={ActivityList} />
983+
{/* ----- Community Calendar Routing ----- */}
970984
<CPProtectedRoute path="/communityportal/calendar" exact component={CommunityCalendar} />
971985
<CPProtectedRoute path="/communityportal/database/design" exact component={EventList} />
972-
<CPProtectedRoute path="/communityportal/activities" exact component={ActivityList} />
986+
973987
<CPProtectedRoute
974988
path="/communityportal/ActivityAttendance"
975989
exact

0 commit comments

Comments
 (0)