Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/hooks/makeMutation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-strict-ignore
import {
ApolloError,
MutationFunction,
Expand Down Expand Up @@ -59,7 +58,10 @@ export function useMutation<TData, TVariables>(
text: intl.formatMessage(commonMessages.readOnly),
});
} else if (err.graphQLErrors.some(isJwtError)) {
user.logout();
if (user.logout) {
user.logout();
}

notify({
status: "error",
text: intl.formatMessage(commonMessages.sessionExpired),
Expand Down Expand Up @@ -87,7 +89,7 @@ export function useMutation<TData, TVariables>(
mutateFn,
{
...result,
status: getMutationStatus(result),
status: getMutationStatus(result as MutationResult<Record<string, any>>),
},
];
}
11 changes: 5 additions & 6 deletions src/hooks/makeQuery.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-strict-ignore
import {
ApolloError,
ApolloQueryResult,
Expand All @@ -11,7 +10,6 @@ import {
import { handleQueryAuthError, useUser } from "@dashboard/auth";
import { PrefixedPermissions } from "@dashboard/graphql/extendedTypes";
import { PermissionEnum, UserPermissionFragment } from "@dashboard/graphql/types.generated";
import { RequireAtLeastOne } from "@dashboard/misc";
import { DocumentNode } from "graphql";
import { useEffect } from "react";
import { useIntl } from "react-intl";
Expand Down Expand Up @@ -100,12 +98,12 @@ export function useQuery<TData, TVariables>(
if (handleError) {
handleError(error);
} else {
handleQueryAuthError(error, notify, user.logout, intl);
handleQueryAuthError(error, notify, user.logout ?? (() => {}), intl);
}
},
skip,
variables: variablesWithPermissions,
});
} as BaseQueryHookOptions<TData, TVariables & Record<PrefixedPermissions, boolean>>);

useEffect(() => {
if (displayLoader) {
Expand All @@ -120,7 +118,7 @@ export function useQuery<TData, TVariables>(

const loadMore = (
mergeFunc: (previousResults: TData, fetchMoreResult: TData) => TData,
extraVariables: RequireAtLeastOne<TVariables>,
extraVariables: Partial<TVariables>,
) =>
queryData.fetchMore({
query,
Expand All @@ -141,7 +139,8 @@ export function useQuery<TData, TVariables>(
}

function makeQuery<TData, TVariables>(query: DocumentNode): UseQueryHook<TData, TVariables> {
return (opts: QueryHookOptions<TData, TVariables>) => useQuery<TData, TVariables>(query, opts);
return (opts?: QueryHookOptions<TData, Omit<TVariables, PrefixedPermissions>>) =>
useQuery<TData, TVariables>(query, opts as QueryHookOptions<TData, TVariables>);
}

export default makeQuery;
3 changes: 1 addition & 2 deletions src/hooks/makeSearch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-strict-ignore
import { QueryResult } from "@apollo/client";
import { DocumentNode } from "graphql";
import { useState } from "react";
Expand Down Expand Up @@ -41,7 +40,7 @@ function makeSearch<TData, TVariables extends SearchVariables>(
variables: {
...opts.variables,
query: searchQuery,
},
} as any,
});

return {
Expand Down
3 changes: 1 addition & 2 deletions src/hooks/makeTopLevelSearch/makeTopLevelSearch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-strict-ignore
import { PageInfoFragment } from "@dashboard/graphql";
import { DocumentNode } from "graphql";

Expand Down Expand Up @@ -40,7 +39,7 @@ function makeTopLevelSearch<TData extends SearchData, TVariables extends SearchV
{
...result.variables,
after: result.data.search.pageInfo.endCursor,
},
} as Partial<TVariables>,
);
}
});
Expand Down
3 changes: 1 addition & 2 deletions src/hooks/useAddressValidation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-strict-ignore
import { AddressTypeInput } from "@dashboard/customers/types";
import {
AccountErrorCode,
Expand All @@ -24,7 +23,7 @@ function useAddressValidation<TInput, TOutput>(
__typename: "AccountError",
code: AccountErrorCode.REQUIRED,
field: "country",
addressType,
addressType: addressType ?? null,
message: "Country required",
};

Expand Down
19 changes: 9 additions & 10 deletions src/hooks/useFilterHandlers.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-strict-ignore
import { renderHook } from "@testing-library/react-hooks";

import { useFilterHandlers } from "./useFilterHandlers";
Expand Down Expand Up @@ -69,7 +68,7 @@ describe("useFilterHandlers", () => {
useFilterHandlers({
getFilterQueryParam: jest.fn(filter => ({
[filter.name]: filter.value,
})),
})) as any,
createUrl,
params: {
activeTab: "tab",
Expand Down Expand Up @@ -98,8 +97,8 @@ describe("useFilterHandlers", () => {
const { result } = renderHook(() =>
useFilterHandlers({
getFilterQueryParam: jest.fn(filter => ({
[filter.name]: filter.value[0],
})),
[filter.name]: filter.value?.[0],
})) as any,
createUrl,
params: {
activeTab: "tab",
Expand Down Expand Up @@ -145,8 +144,8 @@ describe("useFilterHandlers", () => {
const { result } = renderHook(() =>
useFilterHandlers({
getFilterQueryParam: jest.fn(filter => ({
[filter.name]: filter.value[0],
})),
[filter.name]: filter.value?.[0],
})) as any,
createUrl,
params: {
activeTab: "tab",
Expand Down Expand Up @@ -210,8 +209,8 @@ describe("useFilterHandlers", () => {
const { result } = renderHook(() =>
useFilterHandlers({
getFilterQueryParam: jest.fn(filter => ({
[filter.name]: filter.value[0],
})),
[filter.name]: filter.value?.[0],
})) as any,
createUrl,
params: {
activeTab: "tab",
Expand Down Expand Up @@ -243,8 +242,8 @@ describe("useFilterHandlers", () => {
const { result } = renderHook(() =>
useFilterHandlers({
getFilterQueryParam: jest.fn(filter => ({
[filter.name]: filter.value[0],
})),
[filter.name]: filter.value?.[0],
})) as any,
createUrl,
params: {
activeTab: "tab",
Expand Down
3 changes: 1 addition & 2 deletions src/hooks/useFilterHandlers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-strict-ignore
import { IFilter } from "@dashboard/components/Filter/types";
import { ActiveTab, Pagination, Search, Sort } from "@dashboard/types";
import { GetFilterQueryParam, getFilterQueryParams } from "@dashboard/utils/filters";
Expand Down Expand Up @@ -43,7 +42,7 @@ export const useFilterHandlers = <
const hasQuery = !!params.query?.trim();

if (hasQuery || params.sort === "rank") {
prevAsc.current = params.asc;
prevAsc.current = params.asc ?? null;
}
}, [params.asc, params.query, params.sort]);

Expand Down
135 changes: 135 additions & 0 deletions src/hooks/useFormset.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { act, renderHook } from "@testing-library/react-hooks";

import useFormset, { FormsetAtomicData } from "./useFormset";

interface TestData {
name: string;
}

interface TestAdditionalData {
count: number;
}

type TestFormsetData = FormsetAtomicData<TestData, string, TestAdditionalData>;

describe("useFormset", () => {
describe("get", () => {
test("should throw error when item not found", () => {
// Arrange
const initialData: TestFormsetData[] = [
{
id: "1",
label: "Item 1",
value: "value1",
data: { name: "Test 1" },
},
];
const { result } = renderHook(() => useFormset(initialData));

// Act & Assert
expect(() => result.current.get("non-existent-id")).toThrow(
'Item with id "non-existent-id" not found in formset',
);
});

test("should return item when found", () => {
// Arrange
const initialData: TestFormsetData[] = [
{
id: "1",
label: "Item 1",
value: "value1",
data: { name: "Test 1" },
},
];
const { result } = renderHook(() => useFormset(initialData));

// Act
const item = result.current.get("1");

// Assert
expect(item).toEqual({
id: "1",
label: "Item 1",
value: "value1",
data: { name: "Test 1" },
});
});
});

describe("setAdditionalData with merge", () => {
test("should use additionalData directly when item.additionalData is undefined", () => {
// Arrange
const initialData: TestFormsetData[] = [
{
id: "1",
label: "Item 1",
value: "value1",
data: { name: "Test 1" },
// additionalData is undefined
},
];
const { result } = renderHook(() => useFormset(initialData));
const mergeFn = jest.fn((prev: TestAdditionalData, next: TestAdditionalData) => ({
count: prev.count + next.count,
}));

// Act
act(() => {
result.current.setAdditionalData("1", { count: 5 }, mergeFn);
});

// Assert
expect(mergeFn).not.toHaveBeenCalled();
expect(result.current.data[0].additionalData).toEqual({ count: 5 });
});

test("should call merge function when item.additionalData is defined", () => {
// Arrange
const initialData: TestFormsetData[] = [
{
id: "1",
label: "Item 1",
value: "value1",
data: { name: "Test 1" },
additionalData: { count: 10 },
},
];
const { result } = renderHook(() => useFormset(initialData));
const mergeFn = jest.fn((prev: TestAdditionalData, next: TestAdditionalData) => ({
count: prev.count + next.count,
}));

// Act
act(() => {
result.current.setAdditionalData("1", { count: 5 }, mergeFn);
});

// Assert
expect(mergeFn).toHaveBeenCalledWith({ count: 10 }, { count: 5 });
expect(result.current.data[0].additionalData).toEqual({ count: 15 });
});

test("should use additionalData directly when no merge function provided", () => {
// Arrange
const initialData: TestFormsetData[] = [
{
id: "1",
label: "Item 1",
value: "value1",
data: { name: "Test 1" },
additionalData: { count: 10 },
},
];
const { result } = renderHook(() => useFormset(initialData));

// Act
act(() => {
result.current.setAdditionalData("1", { count: 5 });
});

// Assert
expect(result.current.data[0].additionalData).toEqual({ count: 5 });
});
});
});
16 changes: 12 additions & 4 deletions src/hooks/useFormset.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-strict-ignore
import { removeAtIndex } from "@dashboard/utils/lists";

import useStateFromProps from "./useStateFromProps";
Expand Down Expand Up @@ -56,7 +55,13 @@ function useFormset<TData = {}, TValue = any, TAdditionalData = any>(
}

function getItem(id: string): FormsetAtomicData<TData, TValue, TAdditionalData> {
return data.find(item => item.id === id);
const item = data.find(item => item.id === id);

if (!item) {
throw new Error(`Item with id "${id}" not found in formset`);
}

return item;
}

function removeItem(id: string) {
Expand Down Expand Up @@ -86,14 +91,17 @@ function useFormset<TData = {}, TValue = any, TAdditionalData = any>(
const setItemMetadata: FormsetAdditionalDataChange = (
id: string,
additionalData: TAdditionalData,
merge?: (prev, next) => TAdditionalData,
merge?: (prev: TAdditionalData, next: TAdditionalData) => TAdditionalData,
) => {
setData(data =>
data.map(item =>
item.id === id
? {
...item,
additionalData: merge ? merge(item.additionalData, additionalData) : additionalData,
additionalData:
merge && item.additionalData !== undefined
? merge(item.additionalData, additionalData)
: additionalData,
}
: item,
),
Expand Down
5 changes: 2 additions & 3 deletions src/hooks/useListSettings.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-strict-ignore
import useLocalStorage from "@dashboard/hooks/useLocalStorage";
import mergeWith from "lodash/mergeWith";

Expand Down Expand Up @@ -45,13 +44,13 @@ export default function useListSettings<TColumns extends string = string>(
setListSettings(settings => ({
...settings,
[listName]: {
...settings[listName],
...(settings[listName as keyof AppListViewSettings] as ListSettings),
[key]: value,
},
}));

return {
settings: settings[listName] as ListSettings<TColumns>,
settings: settings[listName as keyof AppListViewSettings] as ListSettings<TColumns>,
updateListSettings,
};
}
Loading
Loading