Skip to content

Commit e6c5374

Browse files
committed
Merge branch 'dev' of https://github.com/CodebilityDev/codebility-plus into services-page-improvement
2 parents c9b0c48 + bd0e385 commit e6c5374

23 files changed

Lines changed: 1733 additions & 1381 deletions

File tree

‎apps/codebility/app/(marketing)/profiles/_components/CodevCard.tsx‎

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,7 @@ interface Props {
3131
color: string;
3232
}
3333

34-
const STATUS_CONFIG: Record<
35-
InternalStatus,
36-
{ label: string; className: string }
37-
> = {
34+
const STATUS_CONFIG: Record<InternalStatus, { label: string; className: string }> = {
3835
TRAINING: {
3936
label: "Training",
4037
className:
@@ -118,22 +115,20 @@ const CodevCard = ({ codev, color }: Props) => {
118115
: {};
119116
}, [codev.level, codev.codev_points]);
120117

121-
// Line 119: Enhanced card wrapper with click redirect
122118
return (
123119
<div
124120
className="h-64"
125121
onMouseEnter={() => setHovered(true)}
126122
onMouseLeave={() => setHovered(false)}
127123
>
128-
<div
129-
onClick={() =>
130-
(window.location.href = `https://www.codebility.tech/profiles/${codev.id}`)
131-
}
132-
className="group relative flex h-full w-full cursor-pointer flex-col items-center justify-between rounded-lg border border-white/20 bg-white/10 p-4 shadow-2xl backdrop-blur-md transition-all duration-300 hover:scale-[1.02] hover:bg-white/20 dark:border-white/10 dark:bg-white/5 dark:hover:bg-white/10"
124+
<div
125+
onClick={() => window.location.href = `https://www.codebility.tech/profiles/${codev.id}`}
126+
className="group relative flex h-full w-full flex-col items-center justify-between rounded-lg border border-white/20 bg-white/10 p-4 shadow-2xl backdrop-blur-md transition-all duration-300 cursor-pointer hover:bg-white/20 hover:scale-[1.02] dark:border-white/10 dark:bg-white/5 dark:hover:bg-white/10"
133127
>
134128
{/* Background decoration */}
135129
<div className="from-customBlue-50/30 dark:from-customBlue-950/10 absolute inset-0 bg-gradient-to-br to-purple-50/30 opacity-0 transition-opacity duration-300 group-hover:opacity-100 dark:to-purple-950/10" />
136130
<div className="absolute -right-4 -top-4 h-32 w-32 rounded-full bg-gradient-to-br from-yellow-400/10 to-orange-400/10 opacity-0 blur-2xl transition-opacity duration-500 group-hover:opacity-100" />
131+
137132
<div className="grid w-full grid-cols-4 gap-2">
138133
<div className="col-span-1" />
139134
<div className="relative col-span-2 flex justify-center">
@@ -203,12 +198,7 @@ const CodevCard = ({ codev, color }: Props) => {
203198
<TooltipProvider>
204199
<Tooltip delayDuration={100}>
205200
<TooltipTrigger asChild>
206-
{/* Line 217: Added stopPropagation to prevent card click when button is clicked */}
207-
<Link
208-
href={`/profiles/${codev.id}`}
209-
target="_blank"
210-
onClick={(e) => e.stopPropagation()}
211-
>
201+
<Link href={`/profiles/${codev.id}`} target="_blank" onClick={(e) => e.stopPropagation()}>
212202
<Button
213203
variant="outline"
214204
size="icon"
@@ -247,17 +237,10 @@ const CodevCard = ({ codev, color }: Props) => {
247237
/>
248238
) : null}
249239
</div>
250-
<div
251-
className="relative z-20"
252-
onMouseEnter={(e) => e.stopPropagation()}
253-
onMouseLeave={(e) => e.stopPropagation()}
254-
onClick={(e) => e.stopPropagation()}
255-
>
256-
<CodevHireCodevButton codevId={codev.id} />
257-
</div>
240+
<CodevHireCodevButton codevId={codev.id} hovered={hovered} />
258241
</div>
259242
</div>
260243
);
261244
};
262245

263-
export default CodevCard;
246+
export default CodevCard;

‎apps/codebility/app/(marketing)/profiles/page.tsx‎

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ import { Suspense } from "react";
22
import { UsersSkeleton } from "@/components/ui/skeleton/UsersSkeleton";
33
import { getCodevs } from "@/lib/server/codev.service";
44
import { Codev } from "@/types/home/codev";
5-
import {
6-
getPrioritizedAndFilteredCodevs,
7-
prioritizeCodevs,
8-
} from "@/utils/codev-priority"; // Import the utility
5+
import { prioritizeCodevs } from "@/utils/codev-priority";
6+
import { getQualifiedCodevs } from "@/utils/codev-qualification";
97

108
import Section from "../_shared/CodevsSection";
119
import CodevContainer from "./_components/CodevContainer";
@@ -16,22 +14,33 @@ export const dynamic = "force-dynamic";
1614
export const revalidate = 0;
1715

1816
export default async function Profiles() {
17+
// Fetch all passed codevs (includes admins, mentors, codevs)
1918
const [{ data: allCodevs, error }] = await Promise.all([
20-
getCodevs({ filters: { role_id: 10 } }), // show only Codevs with role_id 10 which is Codev
19+
getCodevs({ filters: { application_status: "passed" } }),
2120
]);
2221

2322
if (error) {
2423
throw new Error("Failed to fetch profiles data");
2524
}
2625

26+
// Convert to array safely
2727
const codevsArray: Codev[] = Array.isArray(allCodevs) ? allCodevs : [];
2828

29-
// Use the utility function with filterAdminAndFailed set to true
30-
const sortedCodevs = getPrioritizedAndFilteredCodevs(
31-
codevsArray,
32-
{ activeStatus: ["active"] },
33-
true,
34-
);
29+
// Filter by qualification criteria (100+ points, passed, available)
30+
// This handles ALL filtering logic - no internal_status restrictions
31+
const qualifiedCodevs = getQualifiedCodevs(codevsArray);
32+
33+
// Apply priority sorting only (no additional filtering)
34+
// Prioritize by: Active projects > No projects, Available > Unavailable
35+
const sortedCodevs = prioritizeCodevs(qualifiedCodevs);
36+
37+
// Debug logging in development
38+
if (process.env.NODE_ENV === "development") {
39+
console.log("📊 PROFILES PAGE STATS:");
40+
console.log(` Total codevs fetched: ${codevsArray.length}`);
41+
console.log(` Qualified codevs: ${qualifiedCodevs.length}`);
42+
console.log(` Final displayed: ${sortedCodevs.length}`);
43+
}
3544

3645
return (
3746
<>
@@ -54,4 +63,4 @@ export default async function Profiles() {
5463
<CodevHireCodevModal />
5564
</>
5665
);
57-
}
66+
}

‎apps/codebility/app/(marketing)/services/page.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ const ServicesPage = async () => {
8989
<ServicesPageContent servicesData={mappedData} />
9090
</ServiceProvider>
9191
</div>
92-
<Footer />
92+
9393
</div>
9494
);
9595
};

‎apps/codebility/app/home/_components/Navbar.tsx‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
} from "@/public/assets/svgs";
1616
import { useUserStore } from "@/store/codev-store";
1717
import { NotificationContainer } from "@/components/notifications/NotificationContainer";
18+
import { AnnouncementButton } from "@/app/home/announcements/AnnouncementButton";
1819

1920
import {
2021
DropdownMenu,
@@ -84,6 +85,9 @@ const Navbar = () => {
8485
role="navigation"
8586
aria-label="User menu"
8687
>
88+
{/* Announcement Button - NEW */}
89+
<AnnouncementButton />
90+
8791
<NotificationContainer />
8892

8993
<div>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"use client";
2+
3+
import React, { useState } from "react";
4+
import { Megaphone } from "lucide-react";
5+
import { AnnouncementModal } from "./AnnouncementModal";
6+
7+
export const AnnouncementButton: React.FC = () => {
8+
const [isModalOpen, setIsModalOpen] = useState(false);
9+
10+
return (
11+
<>
12+
<button
13+
onClick={() => setIsModalOpen(true)}
14+
className="relative rounded-lg p-2 text-gray-600 transition-colors hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800"
15+
aria-label="View announcements"
16+
title="Announcements"
17+
>
18+
<Megaphone className="h-5 w-5" />
19+
</button>
20+
21+
<AnnouncementModal
22+
isOpen={isModalOpen}
23+
onClose={() => setIsModalOpen(false)}
24+
/>
25+
</>
26+
);
27+
};
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"use client";
2+
3+
import React from "react";
4+
import Image from "next/image";
5+
import { AnnouncementPage } from "./types";
6+
7+
interface AnnouncementContentProps {
8+
page: AnnouncementPage;
9+
}
10+
11+
export const AnnouncementContent: React.FC<AnnouncementContentProps> = ({
12+
page,
13+
}) => {
14+
return (
15+
<div className="space-y-4 sm:space-y-6 md:space-y-8">
16+
{/* Banner Image */}
17+
<div className="relative aspect-video w-full overflow-hidden rounded-lg bg-gray-200 dark:bg-gray-800">
18+
<Image
19+
src={page.banner_image}
20+
alt={page.title}
21+
fill
22+
className="object-cover"
23+
sizes="(max-width: 640px) 100vw, (max-width: 768px) 90vw, 800px"
24+
priority
25+
/>
26+
</div>
27+
28+
{/* Title */}
29+
<div>
30+
<h3 className="text-xl sm:text-2xl md:text-3xl font-semibold text-gray-900 dark:text-gray-100">
31+
{page.title}
32+
</h3>
33+
<p className="mt-1 sm:mt-2 text-sm sm:text-base text-gray-500 dark:text-gray-400">
34+
Last updated:{" "}
35+
{new Date(page.last_updated).toLocaleDateString("en-US", {
36+
year: "numeric",
37+
month: "long",
38+
day: "numeric",
39+
})}
40+
</p>
41+
</div>
42+
43+
{/* Content */}
44+
<div className="prose prose-sm sm:prose-base md:prose-lg dark:prose-invert max-w-none">
45+
<div
46+
className="text-gray-700 dark:text-gray-300 text-base sm:text-lg leading-relaxed"
47+
dangerouslySetInnerHTML={{ __html: page.content }}
48+
/>
49+
</div>
50+
</div>
51+
);
52+
};

0 commit comments

Comments
 (0)