mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2025-07-28 12:43:12 +08:00
[resumes][feat] persist filter disclosure opening
This commit is contained in:
@ -142,6 +142,11 @@ export default function ResumeReviewPage() {
|
|||||||
pathname: '/resumes',
|
pathname: '/resumes',
|
||||||
query: {
|
query: {
|
||||||
currentPage: JSON.stringify(1),
|
currentPage: JSON.stringify(1),
|
||||||
|
isFiltersOpen: JSON.stringify({
|
||||||
|
experience: experienceLabel !== undefined,
|
||||||
|
location: locationLabel !== undefined,
|
||||||
|
role: roleLabel !== undefined,
|
||||||
|
}),
|
||||||
searchValue: JSON.stringify(''),
|
searchValue: JSON.stringify(''),
|
||||||
shortcutSelected: JSON.stringify('all'),
|
shortcutSelected: JSON.stringify('all'),
|
||||||
sortOrder: JSON.stringify('latest'),
|
sortOrder: JSON.stringify('latest'),
|
||||||
|
@ -127,6 +127,13 @@ export default function ResumeHomePage() {
|
|||||||
'userFilters',
|
'userFilters',
|
||||||
INITIAL_FILTER_STATE,
|
INITIAL_FILTER_STATE,
|
||||||
);
|
);
|
||||||
|
const [isFiltersOpen, setIsFiltersOpen, isFiltersOpenInit] = useSearchParams<
|
||||||
|
Record<FilterId, boolean>
|
||||||
|
>('isFiltersOpen', {
|
||||||
|
experience: false,
|
||||||
|
location: false,
|
||||||
|
role: false,
|
||||||
|
});
|
||||||
const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false);
|
const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false);
|
||||||
|
|
||||||
const skip = (currentPage - 1) * PAGE_LIMIT;
|
const skip = (currentPage - 1) * PAGE_LIMIT;
|
||||||
@ -137,7 +144,8 @@ export default function ResumeHomePage() {
|
|||||||
isSearchValueInit &&
|
isSearchValueInit &&
|
||||||
isShortcutInit &&
|
isShortcutInit &&
|
||||||
isCurrentPageInit &&
|
isCurrentPageInit &&
|
||||||
isUserFiltersInit
|
isUserFiltersInit &&
|
||||||
|
isFiltersOpenInit
|
||||||
);
|
);
|
||||||
}, [
|
}, [
|
||||||
isTabsValueInit,
|
isTabsValueInit,
|
||||||
@ -146,6 +154,7 @@ export default function ResumeHomePage() {
|
|||||||
isShortcutInit,
|
isShortcutInit,
|
||||||
isCurrentPageInit,
|
isCurrentPageInit,
|
||||||
isUserFiltersInit,
|
isUserFiltersInit,
|
||||||
|
isFiltersOpenInit,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -164,6 +173,7 @@ export default function ResumeHomePage() {
|
|||||||
pathname: router.pathname,
|
pathname: router.pathname,
|
||||||
query: {
|
query: {
|
||||||
currentPage: JSON.stringify(currentPage),
|
currentPage: JSON.stringify(currentPage),
|
||||||
|
isFiltersOpen: JSON.stringify(isFiltersOpen),
|
||||||
searchValue: JSON.stringify(searchValue),
|
searchValue: JSON.stringify(searchValue),
|
||||||
shortcutSelected: JSON.stringify(shortcutSelected),
|
shortcutSelected: JSON.stringify(shortcutSelected),
|
||||||
sortOrder: JSON.stringify(sortOrder),
|
sortOrder: JSON.stringify(sortOrder),
|
||||||
@ -180,6 +190,7 @@ export default function ResumeHomePage() {
|
|||||||
currentPage,
|
currentPage,
|
||||||
router.pathname,
|
router.pathname,
|
||||||
isSearchOptionsInit,
|
isSearchOptionsInit,
|
||||||
|
isFiltersOpen,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const allResumesQuery = trpc.useQuery(
|
const allResumesQuery = trpc.useQuery(
|
||||||
@ -399,11 +410,19 @@ export default function ResumeHomePage() {
|
|||||||
<Disclosure
|
<Disclosure
|
||||||
key={filter.id}
|
key={filter.id}
|
||||||
as="div"
|
as="div"
|
||||||
className="border-t border-slate-200 px-4 pt-6 pb-4">
|
className="border-t border-slate-200 px-4 pt-6 pb-4"
|
||||||
|
defaultOpen={isFiltersOpen[filter.id]}>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<>
|
<>
|
||||||
<h3 className="-mx-2 -my-3 flow-root">
|
<h3 className="-mx-2 -my-3 flow-root">
|
||||||
<Disclosure.Button className="flex w-full items-center justify-between bg-white px-2 py-3 text-slate-400 hover:text-slate-500">
|
<Disclosure.Button
|
||||||
|
className="flex w-full items-center justify-between bg-white px-2 py-3 text-slate-400 hover:text-slate-500"
|
||||||
|
onClick={() =>
|
||||||
|
setIsFiltersOpen({
|
||||||
|
...isFiltersOpen,
|
||||||
|
[filter.id]: !isFiltersOpen[filter.id],
|
||||||
|
})
|
||||||
|
}>
|
||||||
<span className="font-medium text-slate-900">
|
<span className="font-medium text-slate-900">
|
||||||
{filter.label}
|
{filter.label}
|
||||||
</span>
|
</span>
|
||||||
@ -496,72 +515,83 @@ export default function ResumeHomePage() {
|
|||||||
<h3 className="text-md font-medium tracking-tight text-slate-900">
|
<h3 className="text-md font-medium tracking-tight text-slate-900">
|
||||||
Explore these filters
|
Explore these filters
|
||||||
</h3>
|
</h3>
|
||||||
{filters.map((filter) => (
|
{isFiltersOpenInit &&
|
||||||
<Disclosure
|
filters.map((filter) => (
|
||||||
key={filter.id}
|
<Disclosure
|
||||||
as="div"
|
key={filter.id}
|
||||||
className="border-b border-slate-200 pt-6 pb-4">
|
as="div"
|
||||||
{({ open }) => (
|
className="border-b border-slate-200 pt-6 pb-4"
|
||||||
<>
|
defaultOpen={isFiltersOpen[filter.id]}>
|
||||||
<h3 className="-my-3 flow-root">
|
{({ open }) => (
|
||||||
<Disclosure.Button className="flex w-full items-center justify-between py-3 text-sm text-slate-400 hover:text-slate-500">
|
<>
|
||||||
<span className="font-medium text-slate-900">
|
<h3 className="-my-3 flow-root">
|
||||||
{filter.label}
|
<Disclosure.Button
|
||||||
</span>
|
className="flex w-full items-center justify-between py-3 text-sm text-slate-400 hover:text-slate-500"
|
||||||
<span className="ml-6 flex items-center">
|
onClick={() =>
|
||||||
{open ? (
|
setIsFiltersOpen({
|
||||||
<MinusIcon
|
...isFiltersOpen,
|
||||||
aria-hidden="true"
|
[filter.id]: !isFiltersOpen[filter.id],
|
||||||
className="h-5 w-5"
|
})
|
||||||
/>
|
}>
|
||||||
) : (
|
<span className="font-medium text-slate-900">
|
||||||
<PlusIcon
|
{filter.label}
|
||||||
aria-hidden="true"
|
</span>
|
||||||
className="h-5 w-5"
|
<span className="ml-6 flex items-center">
|
||||||
/>
|
{open ? (
|
||||||
)}
|
<MinusIcon
|
||||||
</span>
|
aria-hidden="true"
|
||||||
</Disclosure.Button>
|
className="h-5 w-5"
|
||||||
</h3>
|
/>
|
||||||
<Disclosure.Panel className="space-y-4 pt-4">
|
) : (
|
||||||
<CheckboxList
|
<PlusIcon
|
||||||
description=""
|
aria-hidden="true"
|
||||||
isLabelHidden={true}
|
className="h-5 w-5"
|
||||||
label=""
|
/>
|
||||||
orientation="vertical">
|
)}
|
||||||
{filter.options.map((option) => (
|
</span>
|
||||||
<div
|
</Disclosure.Button>
|
||||||
key={option.value}
|
</h3>
|
||||||
className="[&>div>div:nth-child(1)>input]:text-primary-600 [&>div>div:nth-child(1)>input]:ring-primary-500 flex items-center px-1 text-sm [&>div>div:nth-child(2)>label]:font-normal">
|
<Disclosure.Panel className="space-y-4 pt-4">
|
||||||
<CheckboxInput
|
<CheckboxList
|
||||||
label={option.label}
|
description=""
|
||||||
value={userFilters[filter.id].includes(
|
isLabelHidden={true}
|
||||||
option.value,
|
label=""
|
||||||
)}
|
orientation="vertical">
|
||||||
onChange={(isChecked) =>
|
{filter.options.map((option) => (
|
||||||
onFilterCheckboxChange(
|
<div
|
||||||
isChecked,
|
key={option.value}
|
||||||
filter.id,
|
className="[&>div>div:nth-child(1)>input]:text-primary-600 [&>div>div:nth-child(1)>input]:ring-primary-500 flex items-center px-1 text-sm [&>div>div:nth-child(2)>label]:font-normal">
|
||||||
|
<CheckboxInput
|
||||||
|
label={option.label}
|
||||||
|
value={userFilters[filter.id].includes(
|
||||||
option.value,
|
option.value,
|
||||||
|
)}
|
||||||
|
onChange={(isChecked) =>
|
||||||
|
onFilterCheckboxChange(
|
||||||
|
isChecked,
|
||||||
|
filter.id,
|
||||||
|
option.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<span className="ml-1 text-slate-500">
|
||||||
|
(
|
||||||
|
{getFilterCount(filter.label, option.label)}
|
||||||
)
|
)
|
||||||
}
|
</span>
|
||||||
/>
|
</div>
|
||||||
<span className="ml-1 text-slate-500">
|
))}
|
||||||
({getFilterCount(filter.label, option.label)})
|
</CheckboxList>
|
||||||
</span>
|
<p
|
||||||
</div>
|
className="inline-block cursor-pointer text-sm text-slate-500 underline hover:text-slate-700"
|
||||||
))}
|
onClick={() => onClearFilterClick(filter.id)}>
|
||||||
</CheckboxList>
|
Clear
|
||||||
<p
|
</p>
|
||||||
className="inline-block cursor-pointer text-sm text-slate-500 underline hover:text-slate-700"
|
</Disclosure.Panel>
|
||||||
onClick={() => onClearFilterClick(filter.id)}>
|
</>
|
||||||
Clear
|
)}
|
||||||
</p>
|
</Disclosure>
|
||||||
</Disclosure.Panel>
|
))}
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Disclosure>
|
|
||||||
))}
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user