aboutsummaryrefslogtreecommitdiff
path: root/src/components/hooks/useFilters.ts
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-01-24 13:09:50 +0000
committerFuwn <[email protected]>2026-01-24 13:09:50 +0000
commit396acf3bbbe00a192cb0ea0a9ccf91b1d8d2850b (patch)
treeb9df4ca6a70db45cfffbae6fdd7252e20fb8e93c /src/components/hooks/useFilters.ts
downloadumami-main.tar.xz
umami-main.zip
Initial commitHEADmain
Created from https://vercel.com/new
Diffstat (limited to 'src/components/hooks/useFilters.ts')
-rw-r--r--src/components/hooks/useFilters.ts99
1 files changed, 99 insertions, 0 deletions
diff --git a/src/components/hooks/useFilters.ts b/src/components/hooks/useFilters.ts
new file mode 100644
index 0000000..850e2af
--- /dev/null
+++ b/src/components/hooks/useFilters.ts
@@ -0,0 +1,99 @@
+import { FILTER_COLUMNS, OPERATORS } from '@/lib/constants';
+import { safeDecodeURIComponent } from '@/lib/url';
+import { useFields } from './useFields';
+import { useMessages } from './useMessages';
+import { useNavigation } from './useNavigation';
+
+export function useFilters() {
+ const { formatMessage, labels } = useMessages();
+ const { query } = useNavigation();
+ const { fields } = useFields();
+
+ const operators = [
+ { name: 'eq', type: 'string', label: formatMessage(labels.is) },
+ { name: 'neq', type: 'string', label: formatMessage(labels.isNot) },
+ { name: 'c', type: 'string', label: formatMessage(labels.contains) },
+ { name: 'dnc', type: 'string', label: formatMessage(labels.doesNotContain) },
+ { name: 'i', type: 'array', label: formatMessage(labels.includes) },
+ { name: 'dni', type: 'array', label: formatMessage(labels.doesNotInclude) },
+ { name: 't', type: 'boolean', label: formatMessage(labels.isTrue) },
+ { name: 'f', type: 'boolean', label: formatMessage(labels.isFalse) },
+ { name: 'eq', type: 'number', label: formatMessage(labels.is) },
+ { name: 'neq', type: 'number', label: formatMessage(labels.isNot) },
+ { name: 'gt', type: 'number', label: formatMessage(labels.greaterThan) },
+ { name: 'lt', type: 'number', label: formatMessage(labels.lessThan) },
+ { name: 'gte', type: 'number', label: formatMessage(labels.greaterThanEquals) },
+ { name: 'lte', type: 'number', label: formatMessage(labels.lessThanEquals) },
+ { name: 'bf', type: 'date', label: formatMessage(labels.before) },
+ { name: 'af', type: 'date', label: formatMessage(labels.after) },
+ { name: 'eq', type: 'uuid', label: formatMessage(labels.is) },
+ ];
+
+ const operatorLabels = {
+ [OPERATORS.equals]: formatMessage(labels.is),
+ [OPERATORS.notEquals]: formatMessage(labels.isNot),
+ [OPERATORS.set]: formatMessage(labels.isSet),
+ [OPERATORS.notSet]: formatMessage(labels.isNotSet),
+ [OPERATORS.contains]: formatMessage(labels.contains),
+ [OPERATORS.doesNotContain]: formatMessage(labels.doesNotContain),
+ [OPERATORS.true]: formatMessage(labels.true),
+ [OPERATORS.false]: formatMessage(labels.false),
+ [OPERATORS.greaterThan]: formatMessage(labels.greaterThan),
+ [OPERATORS.lessThan]: formatMessage(labels.lessThan),
+ [OPERATORS.greaterThanEquals]: formatMessage(labels.greaterThanEquals),
+ [OPERATORS.lessThanEquals]: formatMessage(labels.lessThanEquals),
+ [OPERATORS.before]: formatMessage(labels.before),
+ [OPERATORS.after]: formatMessage(labels.after),
+ };
+
+ const typeFilters = {
+ string: [OPERATORS.equals, OPERATORS.notEquals, OPERATORS.contains, OPERATORS.doesNotContain],
+ array: [OPERATORS.contains, OPERATORS.doesNotContain],
+ boolean: [OPERATORS.true, OPERATORS.false],
+ number: [
+ OPERATORS.equals,
+ OPERATORS.notEquals,
+ OPERATORS.greaterThan,
+ OPERATORS.lessThan,
+ OPERATORS.greaterThanEquals,
+ OPERATORS.lessThanEquals,
+ ],
+ date: [OPERATORS.before, OPERATORS.after],
+ uuid: [OPERATORS.equals],
+ };
+
+ const filters = Object.keys(query).reduce((arr, key) => {
+ if (FILTER_COLUMNS[key]) {
+ let operator = 'eq';
+ let value = safeDecodeURIComponent(query[key]);
+ const label = fields.find(({ name }) => name === key)?.label;
+
+ const match = value.match(/^([a-z]+)\.(.*)/);
+
+ if (match) {
+ operator = match[1];
+ value = match[2];
+ }
+
+ return arr.concat({
+ name: key,
+ operator,
+ value,
+ label,
+ });
+ }
+ return arr;
+ }, []);
+
+ const getFilters = (type: string) => {
+ return (
+ typeFilters[type]?.map((key: string | number) => ({
+ type,
+ value: key,
+ label: operatorLabels[key],
+ })) ?? []
+ );
+ };
+
+ return { fields, operators, filters, operatorLabels, typeFilters, getFilters };
+}