mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 12:50:38 +00:00
re-structure to monorepo.
This commit is contained in:
11
packages/webapp/src/hooks/utils/index.tsx
Normal file
11
packages/webapp/src/hooks/utils/index.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
// @ts-nocheck
|
||||
export * from './useLocalStorage';
|
||||
export * from './usePrevious';
|
||||
export * from './useUpdateEffect';
|
||||
export * from './useWatch';
|
||||
export * from './useWhen';
|
||||
export * from './useRequestPdf';
|
||||
export * from './useIntersectionObserver';
|
||||
export * from './useAbilityContext';
|
||||
export * from './useCustomCompareEffect';
|
||||
export * from './useDeepCompareEffect';
|
||||
24
packages/webapp/src/hooks/utils/useAbilityContext.tsx
Normal file
24
packages/webapp/src/hooks/utils/useAbilityContext.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { useAbility } from '@casl/react';
|
||||
import { AbilityContext } from '@/components';
|
||||
|
||||
export const useAbilityContext = () => useAbility(AbilityContext);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const useAbilitiesFilter = () => {
|
||||
const ability = useAbilityContext();
|
||||
|
||||
return React.useCallback(
|
||||
(items) => {
|
||||
return items.filter(
|
||||
(item) =>
|
||||
!item.permission ||
|
||||
ability.can(item.permission.ability, item.permission.subject),
|
||||
);
|
||||
},
|
||||
[ability],
|
||||
);
|
||||
};
|
||||
43
packages/webapp/src/hooks/utils/useCustomCompareEffect.ts
Normal file
43
packages/webapp/src/hooks/utils/useCustomCompareEffect.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { DependencyList, EffectCallback, useEffect, useRef } from 'react';
|
||||
|
||||
const isPrimitive = (val: any) => val !== Object(val);
|
||||
|
||||
type DepsEqualFnType<TDeps extends DependencyList> = (
|
||||
prevDeps: TDeps,
|
||||
nextDeps: TDeps,
|
||||
) => boolean;
|
||||
|
||||
const useCustomCompareEffect = <TDeps extends DependencyList>(
|
||||
effect: EffectCallback,
|
||||
deps: TDeps,
|
||||
depsEqual: DepsEqualFnType<TDeps>,
|
||||
) => {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (!(deps instanceof Array) || !deps.length) {
|
||||
console.warn(
|
||||
'`useCustomCompareEffect` should not be used with no dependencies. Use React.useEffect instead.',
|
||||
);
|
||||
}
|
||||
|
||||
if (deps.every(isPrimitive)) {
|
||||
console.warn(
|
||||
'`useCustomCompareEffect` should not be used with dependencies that are all primitive values. Use React.useEffect instead.',
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof depsEqual !== 'function') {
|
||||
console.warn(
|
||||
'`useCustomCompareEffect` should be used with depsEqual callback for comparing deps list',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ref = useRef<TDeps | undefined>(undefined);
|
||||
|
||||
if (!ref.current || !depsEqual(deps, ref.current)) {
|
||||
ref.current = deps;
|
||||
}
|
||||
useEffect(effect, ref.current);
|
||||
};
|
||||
|
||||
export { useCustomCompareEffect };
|
||||
25
packages/webapp/src/hooks/utils/useDeepCompareEffect.ts
Normal file
25
packages/webapp/src/hooks/utils/useDeepCompareEffect.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// @ts-nocheck
|
||||
import { DependencyList, EffectCallback } from 'react';
|
||||
import isDeepEqualReact from 'fast-deep-equal/react';
|
||||
import { useCustomCompareEffect } from './useCustomCompareEffect';
|
||||
|
||||
const isPrimitive = (val: any) => val !== Object(val);
|
||||
|
||||
const useDeepCompareEffect = (effect: EffectCallback, deps: DependencyList) => {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (!(deps instanceof Array) || !deps.length) {
|
||||
console.warn(
|
||||
'`useDeepCompareEffect` should not be used with no dependencies. Use React.useEffect instead.',
|
||||
);
|
||||
}
|
||||
|
||||
if (deps.every(isPrimitive)) {
|
||||
console.warn(
|
||||
'`useDeepCompareEffect` should not be used with dependencies that are all primitive values. Use React.useEffect instead.',
|
||||
);
|
||||
}
|
||||
}
|
||||
useCustomCompareEffect(effect, deps, isDeepEqualReact);
|
||||
};
|
||||
|
||||
export { useDeepCompareEffect };
|
||||
37
packages/webapp/src/hooks/utils/useIntersectionObserver.tsx
Normal file
37
packages/webapp/src/hooks/utils/useIntersectionObserver.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
|
||||
export function useIntersectionObserver({
|
||||
root,
|
||||
target,
|
||||
onIntersect,
|
||||
threshold = 1.0,
|
||||
rootMargin = '0px',
|
||||
enabled = true,
|
||||
}) {
|
||||
React.useEffect(() => {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) =>
|
||||
entries.forEach((entry) => entry.isIntersecting && onIntersect()),
|
||||
{
|
||||
root: root && root.current,
|
||||
rootMargin,
|
||||
// threshold,
|
||||
threshold: 0.25,
|
||||
},
|
||||
);
|
||||
const el = target && target.current;
|
||||
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
observer.observe(el);
|
||||
|
||||
return () => {
|
||||
observer.unobserve(el);
|
||||
};
|
||||
}, [target.current, enabled, onIntersect, root]);
|
||||
}
|
||||
35
packages/webapp/src/hooks/utils/useLocalStorage.tsx
Normal file
35
packages/webapp/src/hooks/utils/useLocalStorage.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
|
||||
// Hook
|
||||
export function useLocalStorage(key, initialValue) {
|
||||
// State to store our value
|
||||
// Pass initial state function to useState so logic is only executed once
|
||||
const [storedValue, setStoredValue] = React.useState(() => {
|
||||
try {
|
||||
// Get from local storage by key
|
||||
const item = window.localStorage.getItem(key);
|
||||
// Parse stored json or if none return initialValue
|
||||
return item ? JSON.parse(item) : initialValue;
|
||||
} catch (error) {
|
||||
return initialValue;
|
||||
}
|
||||
});
|
||||
// Return a wrapped version of useState's setter function that ...
|
||||
// ... persists the new value to localStorage.
|
||||
const setValue = (value) => {
|
||||
try {
|
||||
// Allow value to be a function so we have same API as useState
|
||||
const valueToStore =
|
||||
value instanceof Function ? value(storedValue) : value;
|
||||
// Save state
|
||||
setStoredValue(valueToStore);
|
||||
// Save to local storage
|
||||
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
||||
} catch (error) {
|
||||
// A more advanced implementation would handle the error case
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
return [storedValue, setValue];
|
||||
}
|
||||
16
packages/webapp/src/hooks/utils/usePrevious.tsx
Normal file
16
packages/webapp/src/hooks/utils/usePrevious.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
// @ts-nocheck
|
||||
import { useRef, useEffect } from 'react';
|
||||
|
||||
|
||||
// Hook
|
||||
export function usePrevious(value) {
|
||||
// The ref object is a generic container whose current property is mutable ...
|
||||
// ... and can hold any value, similar to an instance property on a class
|
||||
const ref = useRef();
|
||||
// Store current value in ref
|
||||
useEffect(() => {
|
||||
ref.current = value;
|
||||
}, [value]); // Only re-run if value changes
|
||||
// Return previous value (happens before update in useEffect above)
|
||||
return ref.current;
|
||||
}
|
||||
39
packages/webapp/src/hooks/utils/useRequestPdf.tsx
Normal file
39
packages/webapp/src/hooks/utils/useRequestPdf.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import useApiRequest from '../useRequest';
|
||||
|
||||
export const useRequestPdf = (url) => {
|
||||
const apiRequest = useApiRequest();
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const [isLoaded, setIsLoaded] = React.useState(false);
|
||||
const [pdfUrl, setPdfUrl] = React.useState('');
|
||||
const [response, setResponse] = React.useState(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
setIsLoading(true);
|
||||
apiRequest
|
||||
.get(url, {
|
||||
headers: { accept: 'application/pdf' },
|
||||
responseType: 'blob',
|
||||
})
|
||||
.then((response) => {
|
||||
// Create a Blob from the PDF Stream.
|
||||
const file = new Blob([response.data], { type: 'application/pdf' });
|
||||
|
||||
// Build a URL from the file
|
||||
const fileURL = URL.createObjectURL(file);
|
||||
|
||||
setPdfUrl(fileURL);
|
||||
setIsLoading(false);
|
||||
setIsLoaded(true);
|
||||
setResponse(response);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
isLoaded,
|
||||
pdfUrl,
|
||||
response,
|
||||
};
|
||||
};
|
||||
20
packages/webapp/src/hooks/utils/useUpdateEffect.tsx
Normal file
20
packages/webapp/src/hooks/utils/useUpdateEffect.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
// @ts-nocheck
|
||||
import { useRef, useEffect } from 'react';
|
||||
|
||||
/**
|
||||
* A custom useEffect hook that only triggers on updates, not on initial mount
|
||||
* Idea stolen from: https://stackoverflow.com/a/55075818/1526448
|
||||
* @param {Function} effect
|
||||
* @param {Array<any>} dependencies
|
||||
*/
|
||||
export function useUpdateEffect(effect, dependencies = []) {
|
||||
const isInitialMount = useRef(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialMount.current) {
|
||||
isInitialMount.current = false;
|
||||
} else {
|
||||
effect();
|
||||
}
|
||||
}, dependencies);
|
||||
}
|
||||
22
packages/webapp/src/hooks/utils/useWatch.tsx
Normal file
22
packages/webapp/src/hooks/utils/useWatch.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
// @ts-nocheck
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
export function useWatch(callback, argument) {
|
||||
const flag = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!flag.current) {
|
||||
flag.current = true;
|
||||
return;
|
||||
}
|
||||
callback(argument);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [argument]);
|
||||
}
|
||||
|
||||
export function useWatchImmediate(callback, argument) {
|
||||
useEffect(() => {
|
||||
callback(argument);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [argument]);
|
||||
}
|
||||
14
packages/webapp/src/hooks/utils/useWhen.tsx
Normal file
14
packages/webapp/src/hooks/utils/useWhen.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
|
||||
export function useWhen(condition, callback) {
|
||||
React.useEffect(() => {
|
||||
if (condition) {
|
||||
callback();
|
||||
}
|
||||
}, [condition, callback]);
|
||||
}
|
||||
|
||||
export function useWhenNot(condition, callback) {
|
||||
return useWhen(!condition, callback);
|
||||
}
|
||||
Reference in New Issue
Block a user