You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 satır
3.4KB

  1. import { cloneDeep, isEqual, unset } from "lodash";
  2. import { ReactNode, createContext, useEffect, useMemo, useState } from "react";
  3. // form
  4. import { useLocation } from "react-router";
  5. import { Dictionary } from "@types";
  6. import useNavigateCustom from "hooks/useNavigateCustom";
  7. // ----------------------------------------------------------------------
  8. const _condition: Dictionary = {};
  9. const initialState = {
  10. initialized: false,
  11. condition: _condition,
  12. get: (key: string): string => "",
  13. initializeCondition: () => {},
  14. addCondition: (condition: Dictionary) => {},
  15. clearCondition: () => {},
  16. };
  17. export const SearchConditionContext = createContext(initialState);
  18. type Props = {
  19. children: ReactNode;
  20. };
  21. export function SearchConditionContextProvider({ children }: Props) {
  22. const [condition, _setCondition] = useState<Dictionary>({});
  23. const [initialized, setInitialized] = useState(false);
  24. const { pathname, search } = useLocation();
  25. const { navigateWhenChanged } = useNavigateCustom();
  26. const setCondition = (after: Dictionary, message?: any) => {
  27. if (message) {
  28. console.log("Contidion Change", { after, message });
  29. }
  30. _setCondition(after);
  31. };
  32. const initializeCondition = () => {
  33. const after: Dictionary = {};
  34. const urlParam = new URLSearchParams(search);
  35. for (const [key, value] of urlParam.entries()) {
  36. after[key] = value;
  37. }
  38. if (!isEqual(after, condition)) {
  39. console.log("initialCondition", { before: condition, after });
  40. setCondition(after, "initializeCondition");
  41. }
  42. setInitialized(true);
  43. };
  44. const get = (key: string) => {
  45. return condition[key] ?? "";
  46. };
  47. const getCondition = useMemo(() => {
  48. return cloneDeep(condition);
  49. }, [condition]);
  50. const addCondition = (additional: Dictionary) => {
  51. if (!initialized) return;
  52. const before = cloneDeep(condition);
  53. const after = cloneDeep(condition);
  54. Object.keys(additional).forEach((key) => {
  55. unset(after, key);
  56. if (additional[key] !== "") {
  57. after[key] = additional[key];
  58. }
  59. });
  60. if (!isEqual(before, after)) {
  61. console.log("addCondition", { additional, before, after });
  62. setCondition(after, "addCondition");
  63. }
  64. };
  65. const searchParams = useMemo(() => {
  66. const params = new URLSearchParams();
  67. if (!initialized) return params;
  68. Object.keys(condition).forEach((key) => {
  69. params.append(key, condition[key]);
  70. });
  71. params.sort();
  72. return params;
  73. }, [condition]);
  74. const applyToURL = () => {
  75. if (!initialized) return;
  76. const params = searchParams;
  77. const searchStr = params.toString();
  78. const url = pathname + (searchStr ? "?" + searchStr : "");
  79. navigateWhenChanged(pathname, condition, "applyToURL");
  80. };
  81. const clearCondition = () => {
  82. setCondition({}, "clearCondition");
  83. setInitialized(false);
  84. console.log("clearCondition");
  85. };
  86. useEffect(() => {
  87. if (initialized) {
  88. console.log("call applyToURL", { condition, initialized });
  89. applyToURL();
  90. }
  91. }, [condition, initialized]);
  92. useEffect(() => {
  93. initializeCondition();
  94. }, [pathname, search]);
  95. return (
  96. <SearchConditionContext.Provider
  97. value={{
  98. condition: getCondition,
  99. initialized,
  100. get,
  101. initializeCondition,
  102. addCondition,
  103. clearCondition,
  104. }}
  105. >
  106. {children}
  107. </SearchConditionContext.Provider>
  108. );
  109. }