Skip to content

Commit

Permalink
updated-filters (code100x#221)
Browse files Browse the repository at this point in the history
* updated-filters

* removed jobFilterQuery action

* provided key to suspense to make it work

* minmal changes

---------

Co-authored-by: aakash singh <[email protected]>
  • Loading branch information
aakash2330 and aakash singh authored Aug 31, 2024
1 parent 5558796 commit 0401a3b
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 162 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ next-env.d.ts
pnpm-lock.yaml
bun.lockb
package-lock.json
yarn.lock
yarn.lock

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,22 @@
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-radio-group": "^1.2.0",
"@radix-ui/react-scroll-area": "^1.1.0",
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slider": "^1.2.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-slot": "^1.1.0",
"dayjs": "^1.11.13",
"@radix-ui/react-switch": "^1.1.0",
"@radix-ui/react-toast": "^1.2.1",
"@types/lodash": "^4.17.7",
"@uidotdev/usehooks": "^2.4.1",
"bcryptjs": "^2.4.3",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"dayjs": "^1.11.13",
"lodash": "^4.17.21",
"lucide-react": "^0.426.0",
"next": "14.2.5",
"next-auth": "^4.24.7",
Expand Down
18 changes: 0 additions & 18 deletions src/actions/job.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
import { getJobFilters } from '@/services/jobs.services';
import { ServerActionReturnType } from '@/types/api.types';
import { getAllJobsAdditonalType, getJobType } from '@/types/jobs.types';
import { redirect } from 'next/navigation';

type additional = {
isVerifiedJob: boolean;
Expand Down Expand Up @@ -132,20 +131,3 @@ export const getJobById = withServerActionAsyncCatcher<
job,
}).serialize();
});

export const jobFilterQuery = async (
queries: JobQuerySchemaType,
baseUrl: string
) => {
const { page, sortby, location, salaryrange, search, workmode } =
JobQuerySchema.parse(queries);
const searchParams = new URLSearchParams({
page: page.toString(),
sortby,
...(search && { search: search.trim() }),
});
location?.map((location) => searchParams.append('location', location));
salaryrange?.map((range) => searchParams.append('salaryrange', range));
workmode?.map((mode) => searchParams.append('workmode', mode));
redirect(`${baseUrl}?${searchParams.toString()}`);
};
23 changes: 11 additions & 12 deletions src/app/jobs/page.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
import AllJobs from '@/components/all-jobs';
import Loader from '@/components/loader';
import APP_PATHS from '@/config/path.config';
import JobFilters from '@/layouts/job-filters';
import JobsHeader from '@/layouts/jobs-header';
import {
JobQuerySchema,
JobQuerySchemaType,
} from '@/lib/validators/jobs.validator';
import { redirect } from 'next/navigation';
import { Suspense } from 'react';

const page = async ({ searchParams }: { searchParams: JobQuerySchemaType }) => {
const validatedSearchParams = JobQuerySchema.parse(searchParams);

const parsedData = JobQuerySchema.safeParse(searchParams);
if (!(parsedData.success && parsedData.data)) {
console.error(parsedData.error);
redirect('/jobs');
}
const parsedSearchParams = parsedData.data;
return (
<div className="container flex gap-5 pt-5">
<JobFilters
searchParams={validatedSearchParams}
baseUrl={APP_PATHS.JOBS}
/>
<JobFilters searchParams={parsedSearchParams} />
<div className="grow">
<JobsHeader
searchParams={validatedSearchParams}
baseUrl={APP_PATHS.JOBS}
/>
<JobsHeader searchParams={parsedSearchParams} />
<Suspense
key={JSON.stringify(parsedSearchParams)}
fallback={
<div className="flex justify-center items-center h-full gap-5 ">
<Loader />
</div>
}
>
<AllJobs searchParams={validatedSearchParams} />
<AllJobs searchParams={parsedSearchParams} />
</Suspense>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/job-landing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const JobLanding = async ({
return (
<div className="max-w-screen-lg mx-auto grid grid-cols-1 gap-6 py-8 pt-10">
<div className="grow px-5">
<JobsHeader searchParams={searchParams} baseUrl="/" />
<JobsHeader searchParams={searchParams} />
<Suspense fallback={<JobCardLoader />}>
<JobCard searchParams={searchParams} />
</Suspense>
Expand Down
28 changes: 9 additions & 19 deletions src/components/pagination-client.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
'use client';
import { jobFilterQuery } from '@/actions/job.action';
import { PaginationNext, PaginationPrevious } from './ui/pagination';
import { JobQuerySchemaType } from '@/lib/validators/jobs.validator';
import useSetQueryParams from '@/hooks/useSetQueryParams';

const PAGE_INCREMENT = 1;
const PaginationPreviousButton = ({
searchParams,
currentPage,
baseUrl,
}: {
searchParams: JobQuerySchemaType;
currentPage: number;
baseUrl: string;
}) => {
const setQueryParams = useSetQueryParams();
return (
<PaginationPrevious
onClick={() =>
jobFilterQuery(
{
...searchParams,
page: currentPage - PAGE_INCREMENT,
},
baseUrl
)
setQueryParams({
page: (currentPage - PAGE_INCREMENT).toString(),
})
}
aria-disabled={currentPage - PAGE_INCREMENT < PAGE_INCREMENT}
role="button"
Expand All @@ -31,27 +26,22 @@ const PaginationPreviousButton = ({
);
};
const PaginationNextButton = ({
searchParams,
currentPage,
totalPages,
baseUrl,
}: {
searchParams: JobQuerySchemaType;
currentPage: number;
totalPages: number;
baseUrl: string;
}) => {
const setQueryParams = useSetQueryParams();
return (
<PaginationNext
role="button"
onClick={() =>
jobFilterQuery(
{
...searchParams,
page: currentPage + PAGE_INCREMENT,
},
baseUrl
)
setQueryParams({
page: (currentPage + PAGE_INCREMENT).toString(),
})
}
aria-disabled={currentPage > totalPages - PAGE_INCREMENT}
className="aria-disabled:pointer-events-none dark:bg-neutral-900 rounded-full bg-neutral-100"
Expand Down
7 changes: 3 additions & 4 deletions src/components/ui/paginator.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
'use client';
import { jobFilterQuery } from '@/actions/job.action';
import { JobQuerySchemaType } from '@/lib/validators/jobs.validator';
import {
PaginationEllipsis,
PaginationItem,
PaginationLink,
} from './pagination';
import useSetQueryParams from '@/hooks/useSetQueryParams';
import { cn } from '@/lib/utils';

export const PaginationPages = ({
currentPage,
totalPages,
searchParams,
baseUrl,
}: {
currentPage: number;
totalPages: number;
searchParams: JobQuerySchemaType;
baseUrl: string;
}) => {
const setQueryParams = useSetQueryParams();
function paginationHandler(page: number) {
jobFilterQuery({ ...searchParams, page: page }, baseUrl);
setQueryParams({ page: page.toString() });
}
const pages: JSX.Element[] = [];
if (totalPages <= 5) {
Expand Down
29 changes: 29 additions & 0 deletions src/hooks/useSetQueryParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import _ from 'lodash';
import { useCallback } from 'react';
import { debounce } from 'lodash';

//pass in key value pairs to update query params
export default function useSetQueryParams() {
const router = useRouter();
const searchParams = useSearchParams();
const pathName = usePathname();

const updateQueryParams = useCallback(
debounce((params) => {
const newSearchParams = new URLSearchParams(searchParams?.toString());
for (const [key, value] of Object.entries(params)) {
//isEmpty reads number as empty too
if (_.isEmpty(value) && typeof value !== 'number') {
newSearchParams.delete(key);
} else {
newSearchParams.set(key, String(value));
}
}
router.push(`${pathName}?${newSearchParams}`, { scroll: false });
}, 300), // 300ms debounce
[router, searchParams, pathName]
);

return updateQueryParams;
}
61 changes: 20 additions & 41 deletions src/layouts/job-filters.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
'use client';
import { jobFilterQuery } from '@/actions/job.action';
import { filters, WorkModeEnums } from '@/lib/constant/jobs.constant';
import {
JobQuerySchema,
Expand All @@ -24,55 +23,38 @@ import {
} from '../components/ui/form';
import { Separator } from '../components/ui/separator';
import { ScrollArea } from '@/components/ui/scroll-area';
import { cn, formatFilterSearchParams } from '@/lib/utils';
import { usePathname } from 'next/navigation';
import APP_PATHS from '@/config/path.config';
import { cn } from '@/lib/utils';
import useSetQueryParams from '@/hooks/useSetQueryParams';
import { useEffect } from 'react';

const JobFilters = ({
searchParams,
baseUrl,
}: {
searchParams: JobQuerySchemaType;
baseUrl: string;
}) => {
const pathname = usePathname();
const isHome = pathname === APP_PATHS.HOME;
const JobFilters = ({ searchParams }: { searchParams: JobQuerySchemaType }) => {
const setQueryParams = useSetQueryParams();
const form = useForm<JobQuerySchemaType>({
resolver: zodResolver(JobQuerySchema),
defaultValues: {
workmode:
searchParams.workmode &&
(formatFilterSearchParams(searchParams.workmode) as WorkModeEnums[]),
salaryrange:
searchParams.salaryrange &&
formatFilterSearchParams(searchParams.salaryrange),
location:
searchParams.location &&
formatFilterSearchParams(searchParams.location),
workmode: searchParams.workmode,
salaryrange: searchParams.salaryrange,
location: searchParams.location,
},
});
async function handleFormSubmit(data: JobQuerySchemaType) {
await jobFilterQuery(
{
...data,
search: searchParams.search,
sortby: searchParams.sortby,
},
baseUrl
);
}

const formValues = form.watch();

useEffect(() => {
if (formValues) {
setQueryParams(formValues);
}
}, [formValues, setQueryParams, searchParams]);

return (
<aside className="rounded-lg border bg-background max-w-[320px] w-full h-fit p-6 sticky top-20">
<aside className="rounded-lg border bg-background max-w-[320px] w-full p-6 h-fit top-20">
<div className="flex items-center justify-between">
<h3 className="font-medium text-base text-primary-text">All Filters</h3>
</div>
<Separator className="my-6" />
<Form {...form}>
<form
onSubmit={form.handleSubmit(handleFormSubmit)}
className=" flex flex-col gap-3"
>
<ScrollArea className={cn('h-96 pr-4', { 'h-64 ': isHome })}>
<form className=" flex flex-col gap-3">
<ScrollArea className={cn('h-fit pr-4')}>
<Accordion
type="multiple"
className="w-full"
Expand Down Expand Up @@ -120,7 +102,6 @@ const JobFilters = ({
(value) => value !== item.value
)
);
form.handleSubmit(handleFormSubmit)();
}}
/>
</FormControl>
Expand Down Expand Up @@ -175,7 +156,6 @@ const JobFilters = ({
(value) => value !== item.value
)
);
form.handleSubmit(handleFormSubmit)();
}}
/>
</FormControl>
Expand Down Expand Up @@ -233,7 +213,6 @@ const JobFilters = ({
(value) => value !== item.value
)
);
form.handleSubmit(handleFormSubmit)();
}}
hidden
/>
Expand Down
Loading

0 comments on commit 0401a3b

Please sign in to comment.