From b43a5791f13639315017998bc3b4e56b1ba0844f Mon Sep 17 00:00:00 2001 From: oliverhuangcode Date: Mon, 5 May 2025 18:32:47 +1000 Subject: [PATCH 1/3] Create functionality for recent and closing date, add basic logic for ascending/descending --- .../src/components/filters/dropdown-sort.tsx | 34 ++++++++++++++ .../src/components/filters/filter-section.tsx | 2 + frontend/src/components/jobs/job-list.tsx | 47 +++++++++++++++---- .../src/context/filter/filter-provider.tsx | 13 ++--- frontend/src/types/filters.ts | 8 ++++ 5 files changed, 86 insertions(+), 18 deletions(-) create mode 100644 frontend/src/components/filters/dropdown-sort.tsx diff --git a/frontend/src/components/filters/dropdown-sort.tsx b/frontend/src/components/filters/dropdown-sort.tsx new file mode 100644 index 0000000..0de9973 --- /dev/null +++ b/frontend/src/components/filters/dropdown-sort.tsx @@ -0,0 +1,34 @@ +import { Select } from "@mantine/core"; +import { useFilterContext } from "@/context/filter/filter-context"; +import { SortBy } from "@/types/filters"; + +export default function DropdownSort() { + const { filters, updateFilters } = useFilterContext(); + + return ( + { diff --git a/frontend/src/components/jobs/job-list.tsx b/frontend/src/components/jobs/job-list.tsx index 405fe2d..470eedc 100644 --- a/frontend/src/components/jobs/job-list.tsx +++ b/frontend/src/components/jobs/job-list.tsx @@ -17,7 +17,7 @@ interface JobListProps { export default function JobList({ jobs }: JobListProps) { //export default function JobList({ jobs, sponsoredJobs }: JobListProps) { - const { selectedJob, setSelectedJob, isLoading, filters } = + const { selectedJob, setSelectedJob, isLoading } = useFilterContext(); const [isModalOpen, setIsModalOpen] = useState(false); const isDesktop = useMediaQuery("(min-width: 1024px)"); @@ -27,34 +27,19 @@ export default function JobList({ jobs }: JobListProps) { copy.sort((a, b) => { // Primary key → highlighted first const highDiff = (b.highlight ? 1 : 0) - (a.highlight ? 1 : 0); - if (highDiff !== 0) return highDiff; - - if (filters.filters.sortBy === "closingdesc") { - const aTime = a.close_date - ? new Date(a.close_date).getTime() - : Number.MAX_SAFE_INTEGER; - const bTime = b.close_date - ? new Date(b.close_date).getTime() - : Number.MAX_SAFE_INTEGER; - return aTime - bTime; - } - - // default "recent" - return ( - new Date(b.created_at).getTime() - - new Date(a.created_at).getTime() - ); + return highDiff; }); return copy; - }, [jobs, filters.filters.sortBy]); + }, [jobs]); + + useEffect(() => { + const selectionMissing = + !selectedJob || !sortedJobs.some((job) => job.id === selectedJob.id); - useEffect(() => { - const selectionMissing = !selectedJob || !sortedJobs.some((job) => job.id === selectedJob.id) - - if (selectionMissing && sortedJobs.length > 0) { - setSelectedJob(sortedJobs[0]) - } - }, [selectedJob, sortedJobs, setSelectedJob]); + if (selectionMissing && sortedJobs.length > 0) { + setSelectedJob(sortedJobs[0]); + } + }, [selectedJob, sortedJobs, setSelectedJob]); if (isLoading) return ; diff --git a/frontend/src/types/filters.ts b/frontend/src/types/filters.ts index 83a53bd..782ff40 100644 --- a/frontend/src/types/filters.ts +++ b/frontend/src/types/filters.ts @@ -15,10 +15,10 @@ export interface JobFilters { } export enum SortBy { - RECENT_DESC = "recentdesc", - RECENT_ASC = "recentasc", - CLOSING_DESC = "closingdesc", - CLOSING_ASC = "closingasc", + RECENT_DESC = "recent_desc", + RECENT_ASC = "recent_asc", + CLOSING_DESC = "closing_desc", + CLOSING_ASC = "closing_asc", } export interface FilterState { From 2f958fb2170fd10b054b70561775db44eedd70b4 Mon Sep 17 00:00:00 2001 From: oliverhuangcode Date: Sat, 10 May 2025 02:59:33 +1000 Subject: [PATCH 3/3] Minor css fixes --- frontend/next.config.ts | 2 +- frontend/src/app/jobs/actions.ts | 15 ++---- .../src/components/filters/dropdown-sort.tsx | 52 ++++++++++--------- .../src/components/filters/filter-section.tsx | 6 +-- frontend/src/components/jobs/job-list.tsx | 3 +- 5 files changed, 37 insertions(+), 41 deletions(-) diff --git a/frontend/next.config.ts b/frontend/next.config.ts index fe2af46..68a6c64 100644 --- a/frontend/next.config.ts +++ b/frontend/next.config.ts @@ -1,7 +1,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - output: 'standalone', + output: "standalone", }; export default nextConfig; diff --git a/frontend/src/app/jobs/actions.ts b/frontend/src/app/jobs/actions.ts index f0df493..b21cb32 100644 --- a/frontend/src/app/jobs/actions.ts +++ b/frontend/src/app/jobs/actions.ts @@ -109,10 +109,10 @@ export async function getJobs( // derive sort object from filters.sortBy const sortMap: Record> = { - recent_desc: { created_at: 1 }, - recent_asc: { created_at: -1 }, - closing_asc: { close_date: 1 }, - closing_desc: { close_date: -1 }, + recent_desc: { created_at: 1 }, + recent_asc: { created_at: -1 }, + closing_desc: { close_date: 1 }, + closing_asc: { close_date: -1 }, }; const sort = sortMap[(filters.sortBy as string) ?? "posted_desc"] ?? { @@ -121,12 +121,7 @@ export async function getJobs( if (minSponsors == 0) { const [jobs, total] = await Promise.all([ - collection - .find(query) - .sort(sort) - .skip(skip) - .limit(PAGE_SIZE) - .toArray(), + collection.find(query).sort(sort).skip(skip).limit(PAGE_SIZE).toArray(), collection.countDocuments(query), ]); return { diff --git a/frontend/src/components/filters/dropdown-sort.tsx b/frontend/src/components/filters/dropdown-sort.tsx index 2835e47..4e3e84c 100644 --- a/frontend/src/components/filters/dropdown-sort.tsx +++ b/frontend/src/components/filters/dropdown-sort.tsx @@ -1,34 +1,36 @@ import { Select } from "@mantine/core"; import { useFilterContext } from "@/context/filter/filter-context"; -import { SortBy } from "@/types/filters"; +import { SortBy } from "@/types/filters"; export default function DropdownSort() { const { filters, updateFilters } = useFilterContext(); return ( - { + if (value) { + updateFilters({ + filters: { + ...filters.filters, + sortBy: value as SortBy, + page: 1, + }, + }); + } + }} + allowDeselect={false} + placeholder="Sort by" + radius={"md"} + className="max-w-36" + /> + ); } diff --git a/frontend/src/components/filters/filter-section.tsx b/frontend/src/components/filters/filter-section.tsx index 3221c1c..b6d0b30 100644 --- a/frontend/src/components/filters/filter-section.tsx +++ b/frontend/src/components/filters/filter-section.tsx @@ -24,10 +24,10 @@ export default function FilterSection({ _totalJobs }: FilterSectionProps) { {isLoading ? "" : totalJobs + " Results"} -
- - +
+ +
); diff --git a/frontend/src/components/jobs/job-list.tsx b/frontend/src/components/jobs/job-list.tsx index 470eedc..afdea82 100644 --- a/frontend/src/components/jobs/job-list.tsx +++ b/frontend/src/components/jobs/job-list.tsx @@ -17,8 +17,7 @@ interface JobListProps { export default function JobList({ jobs }: JobListProps) { //export default function JobList({ jobs, sponsoredJobs }: JobListProps) { - const { selectedJob, setSelectedJob, isLoading } = - useFilterContext(); + const { selectedJob, setSelectedJob, isLoading } = useFilterContext(); const [isModalOpen, setIsModalOpen] = useState(false); const isDesktop = useMediaQuery("(min-width: 1024px)");