diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 1245925..735385b 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -28,12 +28,12 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
-
+
{
- const currentPage = parseInt(page); // like 1
- const itemPerPage = 5; // we want to show 5 item in per pages
- const offset = (currentPage - 1) * itemPerPage; // (1 - 1) * 3 = 0
- const searchSkills = searchParams
- ? searchParams.toLowerCase().split(/[\s,]+/)
- : []; // regular expression to accept inputs separated by comma, space or both
+ const currentPage = parseInt(page, 10) || 1;
+ const itemsPerPage = 5;
+ const offset = (currentPage - 1) * itemsPerPage;
- // In order to get rid of the "error: operator does not exist: json @> json" I mannually cast the skills column to JSONB
- const skillsCondition =
- searchSkills.length > 0
- ? sql.raw(
- `lower("skills"::text)::JSONB @> '${JSON.stringify(searchSkills.map((skill) => skill.toLowerCase()))}'::JSONB`,
+ const whereConditions: SQL[] = [];
+
+ const searchQuery = searchParams?.trim().toLowerCase() || "";
+ const searchTokens = searchQuery ? searchQuery.split(/[\s,]+/) : [];
+
+ // Text field search
+ if (searchQuery) {
+ whereConditions.push(
+ ilike(users.name, `%${searchQuery}%`),
+ ilike(users.location, `%${searchQuery}%`),
+ ilike(users.description, `%${searchQuery}%`)
+ );
+
+ const skillConditions = searchTokens
+ .map((token) => `skill ILIKE '%${token}%'`)
+ .join(" OR ");
+
+ if (skillConditions) {
+ whereConditions.push(
+ sql.raw(`
+ EXISTS (
+ SELECT 1 FROM json_array_elements_text("skills") AS skill
+ WHERE ${skillConditions}
)
- : undefined;
+ `)
+ );
+ }
+ }
+
+ const whereClause = whereConditions.length
+ ? sql`(${sql.join(whereConditions, sql` OR `)})`
+ : undefined;
- const [lengths, profiles] = await Promise.all([
- db.select({ count: sql`count(*)` }).from(users),
- searchParams
- ? db
- .select()
- .from(users)
- .where(
- or(
- ilike(users.name, `%${searchParams}%`),
- ilike(users.location, `%${searchParams}%`),
- ilike(users.description, `%${searchParams}%`),
- skillsCondition,
- ),
- )
- .limit(itemPerPage)
- .offset(offset)
- : db
- .select()
- .from(users)
- .orderBy(sql.raw("RANDOM()"))
- .limit(itemPerPage)
- .offset(offset),
+ const [countResult, profiles] = await Promise.all([
+ db
+ .select({ count: sql`count(*)` })
+ .from(users)
+ .where(whereClause),
+ db
+ .select()
+ .from(users)
+ .where(whereClause)
+ .orderBy(sql.raw("RANDOM()"))
+ .limit(itemsPerPage)
+ .offset(offset),
]);
- const count = lengths[0].count;
+ const count = countResult[0]?.count ?? 0;
+
return (
- {count <= 0 || profiles.length === 0 ? (
-
- ) : (
+ {profiles.length ? (
profiles.map((profile, i) => (
))
+ ) : (
+
)}
1}
search={searchParams}
/>
diff --git a/src/components/shared/sidebar/Sidebar.tsx b/src/components/shared/sidebar/Sidebar.tsx
index ad33676..d740105 100644
--- a/src/components/shared/sidebar/Sidebar.tsx
+++ b/src/components/shared/sidebar/Sidebar.tsx
@@ -32,6 +32,7 @@ const Sidebar = () => {
alt="donate button"
width={130}
height={80}
+ objectFit="cover"
/>