feat(courses): add type, search, and pricing filters to org landing page
- Add Types section to the Filter sidebar with all 4 course types - Add full-text search input centered in the hero (title + description) - Add Pricing section (Free / Paid) based on course cost - Compact hero prop across all 10 themes to halve vertical padding - Children snippet support in all hero themes for the search input - All filters are URL-driven (?types=, ?search=, ?tags=, ?pricing=) - Full-stack: validation schema, DB queries, service, API route, server load, UI
This commit is contained in:
@@ -383,15 +383,21 @@ export const organizationRouter = new Hono()
|
||||
*/
|
||||
.get('/courses/public', zValidator('query', ZGetCoursesBySiteName), async (c) => {
|
||||
try {
|
||||
const { siteName, tags, page, limit } = c.req.valid('query');
|
||||
const tagSlugs = tags
|
||||
?.split(',')
|
||||
.map((value) => value.trim())
|
||||
.filter(Boolean);
|
||||
const { siteName, tags, types, search, pricing, page, limit } = c.req.valid('query');
|
||||
const splitParam = (param: string | undefined) =>
|
||||
param
|
||||
?.split(',')
|
||||
.map((v) => v.trim())
|
||||
.filter(Boolean);
|
||||
const tagSlugs = splitParam(tags);
|
||||
const courseTypes = splitParam(types);
|
||||
const pagination = page !== undefined || limit !== undefined ? { page, limit } : undefined;
|
||||
const courses = await getPublicCourses(
|
||||
siteName,
|
||||
tagSlugs && tagSlugs.length > 0 ? tagSlugs : undefined,
|
||||
tagSlugs?.length ? tagSlugs : undefined,
|
||||
courseTypes?.length ? courseTypes : undefined,
|
||||
search || undefined,
|
||||
pricing || undefined,
|
||||
pagination
|
||||
);
|
||||
|
||||
|
||||
@@ -256,6 +256,9 @@ export async function removeAudienceMember(orgId: string, memberId: number, remo
|
||||
export async function getPublicCourses(
|
||||
siteName: string,
|
||||
tagSlugs?: string[],
|
||||
courseTypes?: string[],
|
||||
search?: string,
|
||||
pricing?: 'free' | 'paid',
|
||||
pagination?: { page?: number; limit?: number }
|
||||
) {
|
||||
try {
|
||||
@@ -286,8 +289,22 @@ export async function getPublicCourses(
|
||||
}
|
||||
}
|
||||
|
||||
const totalCourses = await countPublishedCoursesBySiteName(siteName, filteredCourseIds);
|
||||
const courses = await getPublishedCoursesBySiteName(siteName, filteredCourseIds, limit, offset);
|
||||
const totalCourses = await countPublishedCoursesBySiteName(
|
||||
siteName,
|
||||
filteredCourseIds,
|
||||
courseTypes,
|
||||
search,
|
||||
pricing
|
||||
);
|
||||
const courses = await getPublishedCoursesBySiteName(
|
||||
siteName,
|
||||
filteredCourseIds,
|
||||
courseTypes,
|
||||
search,
|
||||
pricing,
|
||||
limit,
|
||||
offset
|
||||
);
|
||||
const tagsByCourseId = await getCourseTagsByCourseIdsForOrganization(
|
||||
org.id,
|
||||
courses.map((course) => course.id)
|
||||
|
||||
Reference in New Issue
Block a user