Skip to content

Commit

Permalink
fix(List): fix error when using defaultValues
Browse files Browse the repository at this point in the history
  • Loading branch information
mfal committed Dec 16, 2024
1 parent eda0a07 commit bf809a6
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 44 deletions.
69 changes: 32 additions & 37 deletions packages/components/src/components/List/model/filter/Filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,19 @@ import { customPropertyPrefix } from "@/components/List/model/types";
import { difference, unique } from "remeda";
import { FilterValue } from "@/components/List/model/filter/FilterValue";
import z from "zod";
import { toArray } from "@/lib/array/toArray";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const equalsPropertyMatcher: FilterMatcher<any, never, never> = (
const equalsPropertyMatcher: FilterMatcher<unknown, never, never> = (
filterValue,
propertyValue,
) => filterValue === propertyValue;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const stringCastRenderMethod: PropertyValueRenderMethod<any> = (value) =>
const stringCastRenderMethod: PropertyValueRenderMethod<unknown> = (value) =>
String(value);

export class Filter<T, TProp extends PropertyName<T>, TMatchValue> {
public static readonly settingsStorageSchema = z
.record(z.array(z.unknown()))
.record(z.array(z.string()))
.optional();

private _values?: FilterValue[] | undefined;
Expand All @@ -44,31 +43,22 @@ export class Filter<T, TProp extends PropertyName<T>, TMatchValue> {
public readonly renderItem: PropertyValueRenderMethod<TMatchValue>;
public readonly name?: string;
private onFilterUpdateCallbacks = new Set<() => unknown>();
private readonly defaultSelectedValues?: FilterValue[];
private readonly defaultSelectedValues?: readonly NonNullable<TMatchValue>[];

public constructor(list: List<T>, shape: FilterShape<T, TProp, TMatchValue>) {
this.list = list;
this.property = shape.property;
this.mode = shape.mode ?? "one";
this._values = shape.values?.map((v) => new FilterValue(this, v));
this._values = shape.values?.map((v) => FilterValue.create(this, v));
this.matcher = shape.matcher ?? equalsPropertyMatcher;
this.renderItem = shape.renderItem ?? stringCastRenderMethod;
this.name = shape.name;

this.defaultSelectedValues = shape.defaultSelected
? this.values.filter((v) =>
shape.defaultSelected?.some((d) => d === v.value),
)
: undefined;
this.defaultSelectedValues = shape.defaultSelected;
}

private getStoredDefaultSelectedValues() {
const storedValues =
this.list.getStoredFilterDefaultSettings()?.[String(this.property)];

return storedValues
? this.values.filter((v) => storedValues.includes(v.id))
: undefined;
private getStoredSelectedIds() {
return this.list.getStoredFilterDefaultSettings()?.[String(this.property)];
}

public updateInitialState(initialState: InitialTableState) {
Expand Down Expand Up @@ -104,25 +94,27 @@ export class Filter<T, TProp extends PropertyName<T>, TMatchValue> {

private checkFilterMatches(
property: unknown,
filterValue: FilterValue,
filterValueInput: unknown,
): boolean {
if (filterValue === null) {
if (filterValueInput === null) {
return true;
}

const toArray = (val: FilterValue | FilterValue[]): FilterValue[] =>
Array.isArray(val) ? val : [val];

const predicate = (filterValue: FilterValue) =>
this.matcher(filterValue.value as never, property as never);

const toFilterValue = (something: unknown) =>
FilterValue.create(this, something);

if (this.mode === "all") {
return toArray(filterValue).every(predicate);
return toArray(filterValueInput).map(toFilterValue).every(predicate);
} else if (this.mode === "some") {
const filterArr = toArray(filterValue);
return filterArr.length === 0 || filterArr.some(predicate);
const filterArr = toArray(filterValueInput);
return (
filterArr.length === 0 || filterArr.map(toFilterValue).some(predicate)
);
} else if (this.mode === "one") {
return predicate(filterValue);
return predicate(toFilterValue(filterValueInput));
}

throw new Error(`Unknown filter mode '${this.mode}'`);
Expand All @@ -147,7 +139,7 @@ export class Filter<T, TProp extends PropertyName<T>, TMatchValue> {
Array.from(this.getTableColumn().getFacetedUniqueValues().keys())
.flatMap((v) => v)
.filter((v) => v !== undefined && v !== null),
).map((v) => new FilterValue(this, v));
).map((v) => FilterValue.create(this, v));
}

private checkIfValueIsUnknown(value: FilterValue) {
Expand Down Expand Up @@ -179,12 +171,10 @@ export class Filter<T, TProp extends PropertyName<T>, TMatchValue> {
}

public getArrayValue(): FilterValue[] {
const currentValue = this.getValue();
return Array.isArray(currentValue)
? currentValue
: currentValue === null
? []
: [currentValue];
const value = this.getValue();
return value === null
? []
: toArray(value).map((v) => FilterValue.create(this, v));
}

public isValueActive(value: FilterValue): boolean {
Expand Down Expand Up @@ -214,7 +204,8 @@ export class Filter<T, TProp extends PropertyName<T>, TMatchValue> {

public hasChanged(): boolean {
const currentValues = this.getArrayValue().map((v) => v.value);
const initialValues = (this.getInitialValues() ?? []).map((v) => v.value);
const initialValues =
this.getInitialFilterValues()?.map((v) => v.value) ?? [];

return (
currentValues.length !== initialValues.length ||
Expand All @@ -223,7 +214,11 @@ export class Filter<T, TProp extends PropertyName<T>, TMatchValue> {
}

private getInitialValues() {
return this.getStoredDefaultSelectedValues() ?? this.defaultSelectedValues;
return this.getStoredSelectedIds() ?? this.defaultSelectedValues;
}

private getInitialFilterValues() {
return this.getInitialValues()?.map((v) => FilterValue.create(this, v));
}

public resetValues(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,31 @@ import { hash } from "object-code";
export class FilterValue {
public readonly filter: Filter<unknown, string, unknown>;
public readonly value: unknown;
public readonly id: string;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
public constructor(filter: Filter<any, any, any>, value: unknown) {
private constructor(filter: Filter<any, any, any>, value: unknown) {
this.filter = filter;
this.value = value;

if (typeof value === "string" && value.startsWith("FilterValueId@@")) {
this.value = filter.values.find((v) => v.id === value)?.value;
this.id = value;
} else {
this.value = value;
this.id = `FilterValueId@@${this.filter.property}@@${hash(this.value)}`;
}
}

public equals(otherValue: FilterValue) {
return isShallowEqual(this.value, otherValue.value);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public static create(filter: Filter<any, any, any>, value: unknown) {
if (value instanceof FilterValue) {
return value;
}
return new FilterValue(filter, value);
}

public get id() {
return `${this.filter.property}@@${hash(this.value)}`;
public equals(otherValue: FilterValue) {
return isShallowEqual(this.value, otherValue.value);
}

public get isActive() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ export interface FilterShape<T, TProp extends PropertyName<T>, TMatcherValue> {
matcher?: FilterMatcher<T, TProp, TMatcherValue>;
values?: readonly TMatcherValue[];
name?: string;
defaultSelected?: readonly NonNullable<ItemType<TMatcherValue>>[];
defaultSelected?: readonly NonNullable<TMatcherValue>[];
}
2 changes: 2 additions & 0 deletions packages/components/src/lib/array/toArray.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const toArray = <T>(val: T | T[]): T[] =>
Array.isArray(val) ? val : [val];

0 comments on commit bf809a6

Please sign in to comment.