Skip to content

Commit

Permalink
revert UI Settings provider
Browse files Browse the repository at this point in the history
  • Loading branch information
kilbot committed Nov 10, 2024
1 parent 16a4f27 commit 2729517
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 58 deletions.
13 changes: 11 additions & 2 deletions src/screens/main/components/data-table/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,15 @@ interface Props extends HeaderContext<any, any> {
export const DataTableHeader = ({ title, column, header, table }: Props) => {
const disableSort = column.columnDef.meta?.disableSort;
const { sortBy, sortDirection } = table.getState().sorting?.current || {};
const isSorted = sortBy === column.id;

/**
* @NOTE - this is a bit of a hack, but we want the price and total columns to sort on
* `sortable_price` and `sortable_total` instead of `price` and `total`
*/
const isSorted =
column.id === 'price' || column.id === 'total'
? sortBy === `sortable_${column.id}`
: sortBy === column.id;

if (disableSort) {
return (
Expand All @@ -32,7 +40,8 @@ export const DataTableHeader = ({ title, column, header, table }: Props) => {
className="max-w-full"
onPress={() =>
table.setSorting({
sortBy: column.id,
sortBy:
column.id === 'price' || column.id === 'total' ? `sortable_${column.id}` : column.id,
sortDirection: isSorted && sortDirection === 'asc' ? 'desc' : 'asc',
})
}
Expand Down
6 changes: 5 additions & 1 deletion src/screens/main/components/data-table/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import * as React from 'react';

import find from 'lodash/find';
import { useObservableEagerState, useObservableSuspense } from 'observable-hooks';
import {
useObservableEagerState,
useObservableSuspense,
useObservableState,
} from 'observable-hooks';

import { DataTable as Table, DataTableProps } from '@wcpos/components/src/data-table';
import { ErrorBoundary } from '@wcpos/components/src/error-boundary';
Expand Down
7 changes: 1 addition & 6 deletions src/screens/main/components/text-cell.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import * as React from 'react';

import { useObservableEagerState } from 'observable-hooks';
import { Observable, of } from 'rxjs';

import { Text } from '@wcpos/components/src/text';

import type { CellContext } from '@tanstack/react-table';
Expand All @@ -12,8 +9,6 @@ import type { CellContext } from '@tanstack/react-table';
*/
export const TextCell = ({ row, column }: CellContext<any, string>) => {
const item = row.original.document;
const textObservable = item[column.id + '$'] as Observable<string> | undefined;
const text = useObservableEagerState(textObservable ? textObservable : of(null));

return <Text>{text ? String(text) : ''}</Text>;
return <Text>{item[column.id] ? String(item[column.id]) : ''}</Text>;
};
80 changes: 50 additions & 30 deletions src/screens/main/contexts/ui-settings/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
import * as React from 'react';

import { ObservableResource, useObservableSuspense } from 'observable-hooks';
import { ObservableResource } from 'observable-hooks';
import { from } from 'rxjs';
import { switchMap } from 'rxjs/operators';

import log from '@wcpos/utils/src/logger';

import { hydratedSettings } from './hydrate';
import { useUILabel } from './use-ui-label';
import {
UISettingSchema,
UISettingState,
resetToInitialValues,
UISettingID,
patchState,
mergeWithInitalValues,
} from './utils';
import { useAppState } from '../../../../contexts/app-state';

interface UISettingsProviderProps {
children: React.ReactNode;
}

interface SuspendedSettingsProps {
children: React.ReactNode;
resource: ObservableResource<Record<UISettingID, UISettingState<UISettingID>>>;
}

export interface UISettingsContextValue {
states: Record<UISettingID, UISettingState<UISettingID>>;
resources: {
'pos-products': ObservableResource<UISettingState<'pos-products'>>;
'pos-cart': ObservableResource<UISettingState<'pos-cart'>>;
products: ObservableResource<UISettingState<'products'>>;
orders: ObservableResource<UISettingState<'orders'>>;
customers: ObservableResource<UISettingState<'customers'>>;
logs: ObservableResource<UISettingState<'logs'>>;
'reports-orders': ObservableResource<UISettingState<'reports-orders'>>;
};
getLabel: (id: string, key: string) => string;
reset: (id: UISettingID) => Promise<void>;
patch: <T extends UISettingID>(
Expand All @@ -39,13 +44,10 @@ export const UISettingsContext = React.createContext<UISettingsContextValue>(nul
/**
*
*/
const SuspendedSettings = ({ children, resource }: SuspendedSettingsProps) => {
export const UISettingsProvider = ({ children }: UISettingsProviderProps) => {
const { storeDB } = useAppState();
const { getLabel } = useUILabel();

// Use useObservableSuspense to get the hydrated states
const states = useObservableSuspense(resource);

/**
* Reset UI Settings
*/
Expand All @@ -69,31 +71,49 @@ const SuspendedSettings = ({ children, resource }: SuspendedSettingsProps) => {
);

/**
* Context value
* Create a reusable function to generate ObservableResource instances
*/
const createUIResource = React.useCallback(
(id: UISettingID) => {
const observable$ = from(storeDB.addState(`${id}_v2`)).pipe(
switchMap(async (state) => {
await mergeWithInitalValues(id, state);
return state;
})
);
return new ObservableResource(observable$);
},
[storeDB]
);

/**
* Create UI Resources
*/
const resources = React.useMemo(
() => ({
'pos-products': createUIResource('pos-products'),
'pos-cart': createUIResource('pos-cart'),
products: createUIResource('products'),
orders: createUIResource('orders'),
customers: createUIResource('customers'),
logs: createUIResource('logs'),
'reports-orders': createUIResource('reports-orders'),
}),
[createUIResource]
);

/**
* Provide the context value
*/
const value = React.useMemo<UISettingsContextValue>(
const value = React.useMemo(
() => ({
states,
resources,
getLabel,
reset,
patch,
}),
[states, getLabel, reset, patch]
[resources, getLabel, reset, patch]
);

return <UISettingsContext.Provider value={value}>{children}</UISettingsContext.Provider>;
};

/**
*
*/
export const UISettingsProvider = ({ children }: UISettingsProviderProps) => {
const { storeDB } = useAppState();

const resource = React.useMemo(() => {
const settings$ = hydratedSettings(storeDB);
return new ObservableResource(settings$);
}, [storeDB]);

return <SuspendedSettings resource={resource}>{children}</SuspendedSettings>;
};
9 changes: 7 additions & 2 deletions src/screens/main/contexts/ui-settings/use-ui-settings.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import * as React from 'react';

import { useObservableSuspense } from 'observable-hooks';

import { UISettingsContext } from './provider';
import { UISettingID, UISettingState, UISettingSchema } from './utils';

/**
*
*/
export const useUISettings = <T extends UISettingID>(id: T) => {
const context = React.useContext(UISettingsContext);
if (!context) {
throw new Error(`useUISettings must be called within UISettingsProvider`);
}

const { states, getLabel, reset, patch } = context;
const { resources, getLabel, reset, patch } = context;

/**
* Get UI Label
Expand All @@ -19,7 +24,7 @@ export const useUISettings = <T extends UISettingID>(id: T) => {
/**
* Get UI Settings for the specified ID
*/
const uiSettings = states[id] as UISettingState<T>;
const uiSettings = useObservableSuspense(resources[id]) as UISettingState<T>;

return {
uiSettings,
Expand Down
3 changes: 2 additions & 1 deletion src/screens/main/contexts/ui-settings/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export type UISettingSchema<T extends UISettingID> = (typeof initialSettings)[T]
export type UISettingState<T extends UISettingID> = import('rxdb').RxState<UISettingSchema<T>>;

/**
*
* @TODO - this handles the first depth of the schema, but not nested values
* If we change nested schema (eg: columns), we'll need to update this
*/
export const mergeWithInitalValues = async (
id: UISettingID,
Expand Down
16 changes: 14 additions & 2 deletions src/screens/main/hooks/use-collection-reset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,20 @@ export const useCollectionReset = (key: CollectionKey) => {
*/
const clear = React.useCallback(async () => {
const keys = resetCollectionNames[key] || [key];
fastStoreDB.reset(keys);
storeDB.reset(keys);
const collections = [];
// foreach key, get the collection from fastStoreDB.collections and storeDB.collections
keys.forEach((key) => {
collections.push(fastStoreDB.collections[key]);
collections.push(storeDB.collections[key]);
});

await Promise.all(collections.map((collection) => collection.remove()));

/**
* @FIXME - It's proving difficult to do a reset of collections, there is so many subscription
* issues to consider. For now, just reload the page.
*/
window.location.reload();
}, [fastStoreDB, key, storeDB]);

return { clear };
Expand Down
31 changes: 19 additions & 12 deletions src/screens/main/hooks/use-collection.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';

import { useObservableState } from 'observable-hooks';
import { debounceTime, filter } from 'rxjs/operators';
import { filter, tap } from 'rxjs/operators';

import { storeCollections } from '@wcpos/database';
import type { StoreCollections } from '@wcpos/database';
Expand All @@ -28,17 +28,24 @@ export const useCollection = <K extends CollectionKey>(
): { collection: StoreCollections[K]; collectionLabel: string } => {
const t = useT();
const { storeDB } = useAppState();
const collection = useObservableState(
storeDB.reset$.pipe(
filter((collection) => collection.name === key),
/**
* DebounceTime is a bit of a hack, we need to give useReplicationQuery
* time to re-add both collections before we try to access them
*/
debounceTime(100)
),
storeDB.collections[key]
);
const collection = storeDB.collections[key];

/**
* @FIXME - The way collections and queries are handled needs to be rethought,
* it's not enough to just set the collection in state, we need to think about all the
* subscriptions and queries that are using the collection.
*/
// const collection = useObservableState(
// storeDB.reset$.pipe(
// filter((collection) => collection.name === key)
// // /**
// // * DebounceTime is a bit of a hack, we need to give useReplicationQuery
// // * time to re-add both collections before we try to access them
// // */
// // debounceTime(100)
// ),
// storeDB.collections[key]
// );

/**
*
Expand Down
2 changes: 1 addition & 1 deletion src/screens/main/reports/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const Stack = createStackNavigator<CustomersStackParamList>();
*
*/
const ReportsWithProviders = () => {
const { uiSettings } = useUISettings('orders');
const { uiSettings } = useUISettings('reports-orders');
const { wpCredentials, store } = useAppState();
const today = React.useMemo(() => new Date(), []);

Expand Down
2 changes: 1 addition & 1 deletion src/screens/main/tax-rates/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import * as React from 'react';

import { useObservableState } from 'observable-hooks';

import { useReplicationState } from '@wcpos/query';
import { HStack } from '@wcpos/components/src/hstack';
import { Text } from '@wcpos/components/src/text';
import { useReplicationState } from '@wcpos/query';

import { useT } from '../../../contexts/translations';
import SyncButton from '../components/sync-button';
Expand Down

0 comments on commit 2729517

Please sign in to comment.