@applicaster/zapp-react-native-utils
Version:
Applicaster Zapp React Native utilities package
193 lines (143 loc) • 5.81 kB
text/typescript
import { bridgeLogger } from "../../zapp-react-native-bridge/logger";
import { BehaviorSubject } from "rxjs";
import { Storage } from "@applicaster/zapp-react-native-bridge/ZappStorage/Storage";
import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
import { StorageType } from "../appUtils/contextKeysManager/consts";
import { getNamespaceAndKey } from "../appUtils/contextKeysManager/utils";
import { createLogger } from "../logger";
export const { log_verbose, log_debug, log_warning, log_info, log_error } =
createLogger({
category: "StorageMultiSelectProvider",
subsystem: "zapp-react-native-bridge",
parent: bridgeLogger,
});
export interface MultiSelectProvider {
getObservable(): BehaviorSubject<string[]>;
addItem(item: string): Promise<void>;
addItems(items: string[]): Promise<void>;
setSelectedItems(items: string[]): Promise<void>;
removeItem(item: string): Promise<void>;
removeItems(items: string[]): Promise<void>;
removeAllItems(): Promise<void>;
getSelectedItems(): string[];
getSelectedAsync(): Promise<string[]>;
}
export class StorageMultiSelectProvider implements MultiSelectProvider {
// TODO: Unsubscribe and remove when there is no listeners
private static multiSelectProviders: Record<
StorageType,
Record<string, StorageMultiSelectProvider>
> = {
[StorageType.local]: {},
[StorageType.session]: {},
// TODO: not implemented yet
[StorageType.secure]: {},
};
public static getProvider(
keyNamespace: string,
storage: StorageType = StorageType.local
): MultiSelectProvider {
if (!this.multiSelectProviders[storage][keyNamespace]) {
const storageImpl =
storage === StorageType.session ? sessionStorage : localStorage;
this.multiSelectProviders[storage][keyNamespace] =
new StorageMultiSelectProvider(keyNamespace, storageImpl);
}
return this.multiSelectProviders[storage][keyNamespace];
}
private itemSubject: BehaviorSubject<string[] | null>;
private readonly key: string;
private readonly namespace: string;
private constructor(
keyNamespace: string,
private storage: Storage
) {
const { namespace, key } = getNamespaceAndKey(keyNamespace);
if (!key) {
throw new Error("StorageMultiSelectProvider: Key is required");
}
this.key = key;
this.namespace = namespace;
this.storage.addListener?.({ key, namespace }, this.reloadItems);
this.itemSubject = new BehaviorSubject([]);
void this.getSelectedAsync();
log_debug("StorageMultiSelectProvider: Initializing");
}
private reloadItems = async ({ value }: StorageListenerArgs) => {
const selectedItems = value ? value.split(",") : [];
log_debug(
`reloadItems: request to reload items for value: ${value}`,
selectedItems
);
this.itemSubject.next(selectedItems);
};
public getObservable = (): BehaviorSubject<string[]> => this.itemSubject;
private async getSetOfCurrentItems() {
const currentResult: string = await this.storage.getItem(
this.key,
this.namespace
);
return new Set(currentResult ? currentResult.split(",") : []);
}
private async updateItemsAndNotifyObservers(currentItems: Set<string>) {
const arrayOfItems = Array.from(currentItems);
const newValue = arrayOfItems.join(",");
await this.storage.setItem(this.key, newValue, this.namespace);
this.itemSubject.next(arrayOfItems);
}
public addItem = async (item: string): Promise<void> => {
const currentItems = await this.getSetOfCurrentItems();
currentItems.add(item);
log_debug(`addItem: Adding new item: ${item}`);
await this.updateItemsAndNotifyObservers(currentItems);
};
public addItems = async (items: string[]): Promise<void> => {
const currentItems = await this.getSetOfCurrentItems();
items.forEach((item) => currentItems.add(item));
log_debug(
`addItems: Adding new items: ${items.join(
","
)}, current items: ${Array.from(currentItems).join(",")}`
);
await this.updateItemsAndNotifyObservers(currentItems);
};
public removeItem = async (item: string): Promise<void> => {
const currentItems = await this.getSetOfCurrentItems();
currentItems.delete(item);
log_debug(
`removeItem: Removing item: ${item}, current items: ${Array.from(
currentItems
).join(",")}`
);
await this.updateItemsAndNotifyObservers(currentItems);
};
public removeItems = async (items: string[]): Promise<void> => {
const currentItems = await this.getSetOfCurrentItems();
items.forEach((item) => currentItems.delete(item));
log_debug(
`removeItems: Removing items: ${items.join(
","
)}, current items: ${Array.from(currentItems).join(",")}`
);
await this.updateItemsAndNotifyObservers(currentItems);
};
public removeAllItems = async (): Promise<void> => {
await this.storage.removeItem(this.key, this.namespace);
log_debug(`removeAllItems: Removing all items, current items: ${[]}`);
this.itemSubject.next([]);
};
public getSelectedAsync = async (): Promise<string[]> => {
const value = await this.storage.getItem(this.key, this.namespace);
const selectedItems = value ? value.split(",") : [];
this.itemSubject.next(selectedItems);
return selectedItems;
};
public getSelectedItems = (): string[] => {
return this.itemSubject.getValue();
};
setSelectedItems = async (items: string[]): Promise<void> => {
log_debug(`setSelectedItems: Setting selected items: ${items.join(",")}`);
await this.updateItemsAndNotifyObservers(new Set(items));
};
}