Skip to content

Commit 5de143f

Browse files
committed
refactor: modularize Learn page by extracting sections to separate components
1 parent 3759143 commit 5de143f

File tree

4 files changed

+163
-136
lines changed

4 files changed

+163
-136
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import {Search} from "lucide-react";
2+
import RoadmapCard from "@/components/roadmapCard";
3+
4+
export default function AllRoadmapsSection() {
5+
6+
return (
7+
<section>
8+
<h2 className="text-2xl font-semibold mb-4">All Roadmaps</h2>
9+
10+
{/* Search and Filters */}
11+
<div className="bg-white rounded-lg shadow-md p-4 mb-6">
12+
<div className="flex flex-col md:flex-row md:items-center md:space-x-4">
13+
<div className="relative flex-grow mb-4 md:mb-0">
14+
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
15+
<Search size={18} className="text-gray-400"/>
16+
</div>
17+
<input
18+
type="text"
19+
className="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:ring-fsp-core-teal focus:border-fsp-core-teal sm:text-sm"
20+
placeholder="Search roadmaps..."
21+
value={searchTerm}
22+
onChange={(e) => setSearchTerm(e.target.value)}
23+
/>
24+
</div>
25+
26+
<div className="flex flex-wrap gap-2">
27+
<div className="flex items-center">
28+
<input
29+
id="manager-filter"
30+
type="checkbox"
31+
className="h-4 w-4 text-fsp-core-teal focus:ring-fsp-core-teal border-gray-300 rounded"
32+
checked={filters.suggestedByManager}
33+
onChange={(e) => setFilters({...filters, suggestedByManager: e.target.checked})}
34+
/>
35+
<label htmlFor="manager-filter" className="ml-2 block text-sm text-gray-900">
36+
Manager Suggested
37+
</label>
38+
</div>
39+
40+
<div className="flex items-center">
41+
<input
42+
id="favorite-filter"
43+
type="checkbox"
44+
className="h-4 w-4 text-fsp-core-teal focus:ring-fsp-core-teal border-gray-300 rounded"
45+
checked={filters.isFavorite}
46+
onChange={(e) => setFilters({...filters, isFavorite: e.target.checked})}
47+
/>
48+
<label htmlFor="favorite-filter" className="ml-2 block text-sm text-gray-900">
49+
Favorited
50+
</label>
51+
</div>
52+
53+
<select
54+
className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-fsp-core-teal focus:border-fsp-core-teal sm:text-sm rounded-md"
55+
value={filters.capability}
56+
onChange={(e) => setFilters({...filters, capability: e.target.value})}
57+
>
58+
<option value="">All Capabilities</option>
59+
{capabilities.map((capability) => (
60+
<option key={capability} value={capability}>
61+
{capability}
62+
</option>
63+
))}
64+
</select>
65+
</div>
66+
</div>
67+
</div>
68+
69+
{/* Roadmaps Grid */}
70+
{allRoadmaps.length > 0 ? (
71+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
72+
{allRoadmaps.map((roadmap) => (
73+
<RoadmapCard key={roadmap.id} roadmap={roadmap}/>
74+
))}
75+
</div>
76+
) : (
77+
<div className="text-center py-12">
78+
<p className="text-gray-500">No roadmaps found matching your criteria.</p>
79+
</div>
80+
)}
81+
</section>
82+
)
83+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
export default function ContinueLearningSection( {currentRoadmap}: { currentRoadmap: any } ) {
2+
3+
const generateAvatarUrl = (index: number) => {
4+
return `https://i.pravatar.cc/40?img=${index}`;
5+
};
6+
7+
return (
8+
<section className="mb-12">
9+
<h2 className="text-2xl font-semibold mb-4">Continue Learning</h2>
10+
<div className="bg-white rounded-lg shadow-md p-6">
11+
<div className="flex flex-col md:flex-row md:items-center md:justify-between">
12+
<div className="mb-4 md:mb-0">
13+
<h3 className="text-xl font-bold mb-2">{currentRoadmap.title}</h3>
14+
<div className="mb-2">
15+
<span className="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700">
16+
{currentRoadmap.capability}
17+
</span>
18+
</div>
19+
<p className="text-gray-600">{currentRoadmap.description}</p>
20+
</div>
21+
<div className="flex items-center">
22+
<div className="flex -space-x-2 mr-2">
23+
{[...Array(Math.min(3, currentRoadmap.usersLearning || 0))].map((_, i) => (
24+
<img
25+
key={i}
26+
className="inline-block h-8 w-8 rounded-full ring-2 ring-white"
27+
src={generateAvatarUrl(i + 1)}
28+
alt={`User ${i + 1}`}
29+
/>
30+
))}
31+
</div>
32+
<span className="text-sm text-gray-500">
33+
{currentRoadmap.usersLearning} {currentRoadmap.usersLearning === 1 ? 'person' : 'people'} learning
34+
</span>
35+
</div>
36+
</div>
37+
<div className="mt-4">
38+
<button type={"button"} className="bg-fsp-core-teal text-white px-4 py-2 rounded-md hover:opacity-90 transition-opacity">
39+
Continue
40+
</button>
41+
</div>
42+
</div>
43+
</section>
44+
)
45+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import RoadmapCard from "@/components/roadmapCard";
2+
3+
export default function SuggestedRoadmapsSection( {suggestedRoadmaps}: { suggestedRoadmaps: any } ) {
4+
5+
return (
6+
<section className="mb-12">
7+
<h2 className="text-2xl font-semibold mb-4">Suggested Roadmaps</h2>
8+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
9+
{suggestedRoadmaps.map((roadmap) => (
10+
<RoadmapCard key={roadmap.id} roadmap={roadmap} />
11+
))}
12+
</div>
13+
</section>
14+
)
15+
}

src/app/learn/page.tsx

Lines changed: 20 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import {
1717
} from 'lucide-react';
1818
import {Roadmap} from "@/types/Roadmap";
1919
import RoadmapCard from "@/components/roadmapCard";
20+
import ContinueLearningSection from "@/app/learn/continueLearningSection";
21+
import SuggestedRoadmapsSection from "@/app/learn/SuggestedRoadmapsSection";
22+
import AllRoadmapsSection from "@/app/learn/AllRoadmapsSection";
2023

2124
export default async function LearnPage() {
2225
const currentRoadmap = await getCurrentLearningRoadmap();
@@ -33,20 +36,20 @@ export default async function LearnPage() {
3336
});
3437

3538

36-
// Apply filters and search
37-
useEffect(() => {
38-
const applyFiltersAndSearch = async () => {
39-
const filteredRoadmaps = await getAllRoadmaps({
40-
suggestedByManager: filters.suggestedByManager,
41-
isFavorite: filters.isFavorite,
42-
capability: filters.capability,
43-
searchTerm
44-
});
45-
setAllRoadmaps(filteredRoadmaps);
46-
};
47-
48-
applyFiltersAndSearch();
49-
}, [filters, searchTerm]);
39+
// // Apply filters and search
40+
// useEffect(() => {
41+
// const applyFiltersAndSearch = async () => {
42+
// const filteredRoadmaps = await getAllRoadmaps({
43+
// suggestedByManager: filters.suggestedByManager,
44+
// isFavorite: filters.isFavorite,
45+
// capability: filters.capability,
46+
// searchTerm
47+
// });
48+
// setAllRoadmaps(filteredRoadmaps);
49+
// };
50+
//
51+
// applyFiltersAndSearch();
52+
// }, [filters, searchTerm]);
5053

5154
// Generate random avatar URLs for demo purposes
5255
const generateAvatarUrl = (index: number) => {
@@ -58,133 +61,14 @@ export default async function LearnPage() {
5861
<h1 className="text-4xl font-bold text-fsp-core-teal mb-8">Learn</h1>
5962

6063
{/* Continue Learning Section */}
61-
{currentRoadmap && (
62-
<section className="mb-12">
63-
<h2 className="text-2xl font-semibold mb-4">Continue Learning</h2>
64-
<div className="bg-white rounded-lg shadow-md p-6">
65-
<div className="flex flex-col md:flex-row md:items-center md:justify-between">
66-
<div className="mb-4 md:mb-0">
67-
<h3 className="text-xl font-bold mb-2">{currentRoadmap.title}</h3>
68-
<div className="mb-2">
69-
<span className="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700">
70-
{currentRoadmap.capability}
71-
</span>
72-
</div>
73-
<p className="text-gray-600">{currentRoadmap.description}</p>
74-
</div>
75-
<div className="flex items-center">
76-
<div className="flex -space-x-2 mr-2">
77-
{[...Array(Math.min(3, currentRoadmap.usersLearning || 0))].map((_, i) => (
78-
<img
79-
key={i}
80-
className="inline-block h-8 w-8 rounded-full ring-2 ring-white"
81-
src={generateAvatarUrl(i + 1)}
82-
alt={`User ${i + 1}`}
83-
/>
84-
))}
85-
</div>
86-
<span className="text-sm text-gray-500">
87-
{currentRoadmap.usersLearning} {currentRoadmap.usersLearning === 1 ? 'person' : 'people'} learning
88-
</span>
89-
</div>
90-
</div>
91-
<div className="mt-4">
92-
<button className="bg-fsp-core-teal text-white px-4 py-2 rounded-md hover:opacity-90 transition-opacity">
93-
Continue
94-
</button>
95-
</div>
96-
</div>
97-
</section>
98-
)}
64+
<ContinueLearningSection currentRoadmap={currentRoadmap} />
9965

10066
{/* Suggested Roadmaps Section */}
10167
{suggestedRoadmaps.length > 0 && (
102-
<section className="mb-12">
103-
<h2 className="text-2xl font-semibold mb-4">Suggested Roadmaps</h2>
104-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
105-
{suggestedRoadmaps.map((roadmap) => (
106-
<RoadmapCard key={roadmap.id} roadmap={roadmap} />
107-
))}
108-
</div>
109-
</section>
68+
<SuggestedRoadmapsSection suggestedRoadmaps={suggestedRoadmaps} />
11069
)}
11170

112-
{/* All Roadmaps Section */}
113-
<section>
114-
<h2 className="text-2xl font-semibold mb-4">All Roadmaps</h2>
115-
116-
{/* Search and Filters */}
117-
<div className="bg-white rounded-lg shadow-md p-4 mb-6">
118-
<div className="flex flex-col md:flex-row md:items-center md:space-x-4">
119-
<div className="relative flex-grow mb-4 md:mb-0">
120-
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
121-
<Search size={18} className="text-gray-400" />
122-
</div>
123-
<input
124-
type="text"
125-
className="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:ring-fsp-core-teal focus:border-fsp-core-teal sm:text-sm"
126-
placeholder="Search roadmaps..."
127-
value={searchTerm}
128-
onChange={(e) => setSearchTerm(e.target.value)}
129-
/>
130-
</div>
131-
132-
<div className="flex flex-wrap gap-2">
133-
<div className="flex items-center">
134-
<input
135-
id="manager-filter"
136-
type="checkbox"
137-
className="h-4 w-4 text-fsp-core-teal focus:ring-fsp-core-teal border-gray-300 rounded"
138-
checked={filters.suggestedByManager}
139-
onChange={(e) => setFilters({...filters, suggestedByManager: e.target.checked})}
140-
/>
141-
<label htmlFor="manager-filter" className="ml-2 block text-sm text-gray-900">
142-
Manager Suggested
143-
</label>
144-
</div>
145-
146-
<div className="flex items-center">
147-
<input
148-
id="favorite-filter"
149-
type="checkbox"
150-
className="h-4 w-4 text-fsp-core-teal focus:ring-fsp-core-teal border-gray-300 rounded"
151-
checked={filters.isFavorite}
152-
onChange={(e) => setFilters({...filters, isFavorite: e.target.checked})}
153-
/>
154-
<label htmlFor="favorite-filter" className="ml-2 block text-sm text-gray-900">
155-
Favorited
156-
</label>
157-
</div>
158-
159-
<select
160-
className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-fsp-core-teal focus:border-fsp-core-teal sm:text-sm rounded-md"
161-
value={filters.capability}
162-
onChange={(e) => setFilters({...filters, capability: e.target.value})}
163-
>
164-
<option value="">All Capabilities</option>
165-
{capabilities.map((capability) => (
166-
<option key={capability} value={capability}>
167-
{capability}
168-
</option>
169-
))}
170-
</select>
171-
</div>
172-
</div>
173-
</div>
174-
175-
{/* Roadmaps Grid */}
176-
{allRoadmaps.length > 0 ? (
177-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
178-
{allRoadmaps.map((roadmap) => (
179-
<RoadmapCard key={roadmap.id} roadmap={roadmap} />
180-
))}
181-
</div>
182-
) : (
183-
<div className="text-center py-12">
184-
<p className="text-gray-500">No roadmaps found matching your criteria.</p>
185-
</div>
186-
)}
187-
</section>
71+
<AllRoadmapsSection />
18872
</main>
18973
);
19074
}

0 commit comments

Comments
 (0)