attempt to fix unit tests.

This commit is contained in:
Jordan Hewitt 2024-06-27 14:31:59 -07:00
parent 4561cfacd4
commit 562cae7f5a
20 changed files with 489 additions and 259 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"jest.jestCommandLine": "node_modules/.bin/jest",
}

View File

@ -1,9 +1,9 @@
import { Tabs } from 'expo-router';
import React from 'react';
import { TabBarIcon } from '@/components/navigation/TabBarIcon';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
import { TabBarIcon } from '@/components/navigation/TabBarIcon';
export default function TabLayout() {
const colorScheme = useColorScheme();
@ -17,18 +17,18 @@ export default function TabLayout() {
<Tabs.Screen
name="index"
options={{
title: 'Home',
title: 'Conversion',
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'home' : 'home-outline'} color={color} />
<TabBarIcon name={focused ? 'recording' : 'recording-outline'} color={color} />
),
}}
/>
<Tabs.Screen
name="explore"
name="product-editor"
options={{
title: 'Explore',
title: 'Products',
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'code-slash' : 'code-slash-outline'} color={color} />
<TabBarIcon name={focused ? 'recording' : 'recording-outline'} color={color} />
),
}}
/>

View File

@ -1,102 +0,0 @@
import Ionicons from '@expo/vector-icons/Ionicons';
import { StyleSheet, Image, Platform } from 'react-native';
import { Collapsible } from '@/components/Collapsible';
import { ExternalLink } from '@/components/ExternalLink';
import ParallaxScrollView from '@/components/ParallaxScrollView';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
export default function TabTwoScreen() {
return (
<ParallaxScrollView
headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }}
headerImage={<Ionicons size={310} name="code-slash" style={styles.headerImage} />}>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Explore</ThemedText>
</ThemedView>
<ThemedText>This app includes example code to help you get started.</ThemedText>
<Collapsible title="File-based routing">
<ThemedText>
This app has two screens:{' '}
<ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> and{' '}
<ThemedText type="defaultSemiBold">app/(tabs)/explore.tsx</ThemedText>
</ThemedText>
<ThemedText>
The layout file in <ThemedText type="defaultSemiBold">app/(tabs)/_layout.tsx</ThemedText>{' '}
sets up the tab navigator.
</ThemedText>
<ExternalLink href="https://docs.expo.dev/router/introduction">
<ThemedText type="link">Learn more</ThemedText>
</ExternalLink>
</Collapsible>
<Collapsible title="Android, iOS, and web support">
<ThemedText>
You can open this project on Android, iOS, and the web. To open the web version, press{' '}
<ThemedText type="defaultSemiBold">w</ThemedText> in the terminal running this project.
</ThemedText>
</Collapsible>
<Collapsible title="Images">
<ThemedText>
For static images, you can use the <ThemedText type="defaultSemiBold">@2x</ThemedText> and{' '}
<ThemedText type="defaultSemiBold">@3x</ThemedText> suffixes to provide files for
different screen densities
</ThemedText>
<Image source={require('@/assets/images/react-logo.png')} style={{ alignSelf: 'center' }} />
<ExternalLink href="https://reactnative.dev/docs/images">
<ThemedText type="link">Learn more</ThemedText>
</ExternalLink>
</Collapsible>
<Collapsible title="Custom fonts">
<ThemedText>
Open <ThemedText type="defaultSemiBold">app/_layout.tsx</ThemedText> to see how to load{' '}
<ThemedText style={{ fontFamily: 'SpaceMono' }}>
custom fonts such as this one.
</ThemedText>
</ThemedText>
<ExternalLink href="https://docs.expo.dev/versions/latest/sdk/font">
<ThemedText type="link">Learn more</ThemedText>
</ExternalLink>
</Collapsible>
<Collapsible title="Light and dark mode components">
<ThemedText>
This template has light and dark mode support. The{' '}
<ThemedText type="defaultSemiBold">useColorScheme()</ThemedText> hook lets you inspect
what the user's current color scheme is, and so you can adjust UI colors accordingly.
</ThemedText>
<ExternalLink href="https://docs.expo.dev/develop/user-interface/color-themes/">
<ThemedText type="link">Learn more</ThemedText>
</ExternalLink>
</Collapsible>
<Collapsible title="Animations">
<ThemedText>
This template includes an example of an animated component. The{' '}
<ThemedText type="defaultSemiBold">components/HelloWave.tsx</ThemedText> component uses
the powerful <ThemedText type="defaultSemiBold">react-native-reanimated</ThemedText> library
to create a waving hand animation.
</ThemedText>
{Platform.select({
ios: (
<ThemedText>
The <ThemedText type="defaultSemiBold">components/ParallaxScrollView.tsx</ThemedText>{' '}
component provides a parallax effect for the header image.
</ThemedText>
),
})}
</Collapsible>
</ParallaxScrollView>
);
}
const styles = StyleSheet.create({
headerImage: {
color: '#808080',
bottom: -90,
left: -35,
position: 'absolute',
},
titleContainer: {
flexDirection: 'row',
gap: 8,
},
});

View File

@ -1,25 +1,31 @@
import { Image, StyleSheet, Platform } from 'react-native';
import { Image, StyleSheet, Platform, ImageBackground } from 'react-native';
import { HelloWave } from '@/components/HelloWave';
import ParallaxScrollView from '@/components/ParallaxScrollView';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
import { SafeAreaView } from 'react-native-safe-area-context';
import { LengthInput } from '@/components/LengthInput';
import { setupStore } from '../store';
import { MeasurementInput } from '@/components/LengthInput';
import { setupStore, useAppDispatch } from '../store';
import { selectProducts } from '@/features/product/productSlice';
import { Product } from '@/lib/product';
import { ProductTile } from '@/components/ProductTyle';
import { Measure, area, length } from 'enheter';
export default function HomeScreen() {
const store = setupStore();
const products = useAppDispatch(selectProducts);
function calculatePrice() {
}
const selectProduct = (product : Product) => {
}
return (
<SafeAreaView>
<LengthInput onLengthSet={calculatePrice} />
{}
<MeasurementInput onMeasurementSet={calculatePrice} />
{products.map((product) => {
<ProductTile product={product} onProductSelected={selectProduct} />
})}
</SafeAreaView>
);
}

View File

@ -0,0 +1,37 @@
import { Image, StyleSheet, Platform, ImageBackground } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { MeasurementInput } from '@/components/LengthInput';
import { setupStore, useAppDispatch } from '../store';
import { selectProducts } from '@/features/product/productSlice';
import { Product } from '@/lib/product';
import { ProductTile } from '@/components/ProductTyle';
import { Measure, area, length } from 'enheter';
export default function HomeScreen() {
return (
<SafeAreaView>
<ProductEditor />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
titleContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
stepContainer: {
gap: 8,
marginBottom: 8,
},
reactLogo: {
height: 178,
width: 290,
bottom: 0,
left: 0,
position: 'absolute',
},
});

View File

@ -1,3 +1,4 @@
import { useDispatch, useSelector } from 'react-redux';
import { combineReducers, configureStore } from '@reduxjs/toolkit';
import { rememberReducer, rememberEnhancer } from 'redux-remember';
import reducers from "@/features/product/productSlice"
@ -30,3 +31,6 @@ export function setupStore(preloadedState: Partial<RootState> = {
export type RootState = ReturnType<typeof rootReducer>;
export type AppStore = ReturnType<typeof setupStore>;
export type AppDispatch = AppStore['dispatch'];
export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
export const useAppSelector = useSelector.withTypes<RootState>();

View File

@ -3,15 +3,15 @@ import { useState } from "react";
import { Button, StyleSheet, Text, TextInput, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
export type t_length_unit = "foot" | "inch"
export type mode = "length" | "area"
export type LengthInputProps = {
onLengthSet?: (length: Measure<"length">) => any,
onAreaSet?: (area: Measure<"area">) => any,
onMeasurementSet?: (length: Measure<"length" | "area">) => any,
isArea?: boolean,
}
export type t_length_unit = "foot" | "inch"
export function LengthInput(props: LengthInputProps) {
export function MeasurementInput(props: LengthInputProps) {
const [length, setLength] = useState(null as null | number);
const [width, setWidth] = useState(null as null | number);
@ -22,11 +22,11 @@ export function LengthInput(props: LengthInputProps) {
setLength(value);
if (!props.isArea) {
const len = en_length(unit, value)
props.onLengthSet && props.onLengthSet(len)
props.onMeasurementSet && props.onMeasurementSet(len)
} else {
const en_unit = unit == "foot" ? "squareFoot" : "squareInch"
const ar = en_area(en_unit, value);
props.onAreaSet && props.onAreaSet(ar);
props.onMeasurementSet && props.onMeasurementSet(ar);
}
}
@ -34,7 +34,7 @@ export function LengthInput(props: LengthInputProps) {
const value = parseFloat(text);
setLength(value);
const len = en_length(unit, value)
props.onLengthSet && props.onLengthSet(len)
props.onMeasurementSet && props.onMeasurementSet(len)
}
return (

View File

@ -0,0 +1,45 @@
import { Product } from "@/lib/product";
import Ionicons from "@expo/vector-icons/Ionicons";
import React from "react";
import { ChangeEvent, SetStateAction, useState } from "react";
import { NativeSyntheticEvent, StyleSheet, Text, TextInput, TextInputChangeEventData, TextInputProps, TouchableHighlight, View } from "react-native";
export type ProductAttributeChangeFunc = (product_id: string, key: string, newValue: string) => any;
export type ProductAttributeDeleteFunc = (product_id: string, key: string) => any;
export type ProductAttributeProps = { product: Product, key: string, value: string, onChange?: ProductAttributeChangeFunc, onDelete?: ProductAttributeChangeFunc, };
export default function ProductAttributeEditor({ product, key, value, onDelete, onChange }: ProductAttributeProps) {
const [doEdit, setDoEdit] = useState(true);
const [newValue, setNewValue] = useState(value);
const doChange = (e : any) => {
setNewValue(e.target.value);
}
return (
<View>
<Text>
{key}
</Text>
<View>
<TouchableHighlight
onPress={() => onDelete && onDelete(product.id, key, value)}
aria-label="Delete Attribute">
<Ionicons name="trash-bin-outline" />
</TouchableHighlight>
{doEdit ?
(<Text>
{newValue}
</Text>) : (
<TextInput value={newValue} onChange={doChange} />
)
}
</View>
</View>
)
}
const style = StyleSheet.create({
});

View File

@ -0,0 +1,47 @@
import { useAppDispatch, useAppSelector } from "@/app/store"
import { deleteProduct, selectProducts, updateProduct } from "@/features/product/productSlice"
import { Product } from "@/lib/product";
import { FlatListComponent, StyleSheet, Text } from "react-native";
import { FlatList } from "react-native-reanimated/lib/typescript/Animated";
import { SafeAreaView } from "react-native-safe-area-context";
import { ProductEditorItem } from "./ProductEditorItem";
export const ProductEditor = () => {
const products = useAppSelector(selectProducts) as Product [];
const dispatch = useAppDispatch();
function onProductDeleted(product_id: string) {
dispatch(deleteProduct(product_id));
}
function onProductUpdated(product_id: string, product: Product) {
dispatch(updateProduct(product));
}
return (
<SafeAreaView>
<FlatList
data={products}
renderItem={
({item}) => {
return (
<ProductEditorItem
product={item}
onProductDeleted={onProductDeleted}
onProductUpdated={onProductUpdated}
/>
)
}
}
/>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
product: {
}
})

View File

@ -0,0 +1,58 @@
import { Product } from "@/lib/product"
import { useState } from "react"
import { StyleSheet, Text, TouchableHighlight } from "react-native"
import { FlatList } from "react-native-reanimated/lib/typescript/Animated";
import ProductAttributeEditor from "./ProductAttributeEditor";
export type ProductUpdatedFunc = (product_id : string, product : Product) => any;
export type ProductDeletedFunc = (product_id : string) => any;
export type ProductEditorItemProps = {
product : Product,
onProductUpdated?: ProductUpdatedFunc,
onProductDeleted?: ProductDeletedFunc,
}
export const ProductEditorItem = ({ product, onProductUpdated, onProductDeleted }: ProductEditorItemProps) => {
const [showAttributes, setShowAttributes] = useState(true);
function onAttributeChanged(product_id: string, key: string, newValue: string) {
product.attributes[key] = newValue;
onProductUpdated && onProductUpdated(product_id, product);
}
function onAttributeDelete(product_id: string, key: string) {
product.removeAttribute(key);
onProductUpdated && onProductUpdated(product_id, product);
}
return (
<TouchableHighlight
onPress={() => setShowAttributes(true)}
>
<Text style={styles.product}>{product.attributes.name || `Product ${product.id}`} </Text>
{showAttributes &&
(
<FlatList
data={product.attributesAsList}
renderItem={({ item }) => (
<ProductAttributeEditor
product={product}
key={item.key}
value={item.value}
onChange={onAttributeChanged}
onDelete={onAttributeDelete}
/>
)}
/>
)
}
</TouchableHighlight>
)
}
const styles = StyleSheet.create({
product: {},
})

View File

@ -0,0 +1,44 @@
import { Product } from "@/lib/product"
import { ImageBackground, StyleProp, StyleSheet, Text, ViewStyle } from "react-native";
import { AnimatedStyle } from "react-native-reanimated";
import { View } from "react-native-reanimated/lib/typescript/Animated";
export type OnProductSelectedFunc = (product : Product) => any;
type MyStyle = StyleProp<AnimatedStyle<StyleProp<ViewStyle>>>;
export type ProductTileProps = {
product: (Product),
onProductSelected?: OnProductSelectedFunc,
style?: {
tile?: MyStyle,
image?: MyStyle,
}
}
const FALLBACK_IMAGE = "";
export function ProductTile ({product, onProductSelected, style} : ProductTileProps) {
const src = product.attributes.image || FALLBACK_IMAGE;
return (
<View style={style?.tile}>
<ImageBackground
src={src}
resizeMode="cover"
style={styles.image}
>
<Text style={styles.text}>{product.attributes.name || `Product ${product.id}`}</Text>
<Text style={styles.text}>{ product.pricePerUnit.toString() } / {product.measurement.value} {product.measurement.unit.symbol} </Text>
</ImageBackground>
</View>
);
}
const styles = StyleSheet.create({
image: {
},
text: {
},
})

View File

@ -0,0 +1,27 @@
import { Product } from "@/lib/product"
import ProductAttributeEditor from "../ProductAttributeEditor"
import { renderWithProviders } from "./util"
import { area } from "enheter"
import {screen} from '@testing-library/react-native';
import React from "react";
describe("Product editor tests", () => {
it("Product attributes render", () => {
const product = new Product(
100,
area("squareFoot", 4 * 7)
);
const onChange = jest.fn();
const onDelete = jest.fn();
renderWithProviders(
<ProductAttributeEditor
key="Name"
value="product"
product={product}
onChange={onChange}
onDelete={onDelete}
/>);
expect(screen.findByLabelText("Delete Attribute")).not.toBeNull();
})
})

View File

@ -0,0 +1,41 @@
import { RenderOptions, render } from "@testing-library/react-native";
import { PropsWithChildren, ReactElement } from "react";
import { Provider } from "react-redux";
import { setupStore, RootState } from "@/app/store";
import { Price, Product } from "@/lib/product";
import { area, length } from "enheter";
export interface ExtendedRenderOptions extends Omit<RenderOptions, 'queries'> {
preloadedState?: Partial<RootState>;
store?: any; // TODO
}
const basicState = {
products: [
new Product(20.00, length("foot", 5), {name: "Track"}),
new Product(20.00, area("squareFoot", 5), {name: "Shelf"}),
]
}
export function renderWithProviders(
ui: ReactElement,
preloadedState = basicState,
extendedRenderOptions: ExtendedRenderOptions = {},
) {
const {
// Automatically create a store instance if no store was passed in
store = setupStore(preloadedState as Partial<RootState>),
...renderOptions
} = extendedRenderOptions;
const Wrapper = ({ children }: PropsWithChildren) => (
<Provider store={store}>{children}</Provider>
);
// Return an object with the store and all of RTL's query functions
return {
store,
...render(ui, { wrapper: Wrapper, ...renderOptions })
};
}

View File

@ -0,0 +1,11 @@
import { Price, Product } from "@/lib/product";
import { area, length } from "enheter";
export default [
// Sheet goods
new Product(new Price("USD", 35), area("squareFoot", 4 * 8), {name: "Plywood"}),
new Product(new Price("USD", 45), area("squareFoot", 4 * 8), {name: "OSB"}),
new Product(new Price("USD", 45), area("squareFoot", 4 * 8), {name: "MDF"}),
// Beams and trim
new Product(new Price("USD", 1), length("foot", 1), {name: "trim"}),
]

View File

@ -1,5 +1,7 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
};
preset: 'jest-expo',
"transformIgnorePatterns": [
"node_modules/(?!@ngrx|(?!deck.gl)|ng-dynamic)"
]
};

View File

@ -1,24 +1,24 @@
import { length } from "enheter";
import { AreaProduct, LengthProduct, price } from "../product";
import { Product } from "../product";
describe("Product tests", () => {
it(`Length product gives correct price for a shorter length`, () => {
const standard = new LengthProduct(price("USD", 20), length("foot", 4));
const standard = new Product(20, length("foot", 4));
const comparison = standard.priceFor(length("foot", 2));
expect(comparison.value).toEqual(10);
expect(comparison).toEqual(10);
});
it(`Length product gives correct price for a longer length`, () => {
const standard = new LengthProduct(price("USD", 20), length("foot", 4));
const standard = new Product(20, length("foot", 4));
const comparison = standard.priceFor(length("foot", 8));
expect(comparison.value).toEqual(40);
expect(comparison).toEqual(40);
});
it(`Length product gives correct price if different units`, () => {
const standard = new LengthProduct(price("USD", 10), length("foot", 1));
const standard = new Product(10, length("foot", 1));
const comparison = standard.priceFor(length("inch", 24));
expect(comparison.value).toEqual(20);
expect(comparison).toEqual(20);
});
});

View File

@ -1,63 +1,58 @@
import {length as en_length, area as en_area} from "enheter"
import {Measure, LengthUnit, AreaUnit, } from "enheter"
import uuid from "react-native-uuid";
export type Id = string;
export type Currency = "USD";
export class Price<C extends Currency> {
constructor(public value : number) {}
}
export const CURRENCY_SYMBOLS : Map<"USD", string> = {
"USD": "$",
};
export function price(c : Currency, value : number) {
return new Price<typeof c>(value);
export class Price {
constructor(public currency : Currency, public value : number) {}
public toString() {
const sym = CURRENCY_SYMBOLS.get(this.currency);
return `${sym} ${Math.round(this.value)}`;
}
}
export type ProductAttributes = {
id?: string,
name?: string,
image?: string,
description?: string,
depth?: string,
currency?: Currency,
[key:string]: any,
}
export abstract class Product {
id?: Id
constructor(public pricePerUnit : Price<Currency>, public attributes : ProductAttributes = {}) {}
public abstract priceFor(measure : Measure<"length"> | Measure<"area">) : Price<Currency>;
}
interface ILength {
length : Measure<"length">
}
interface IArea {
area: Measure<"area">
}
export class LengthProduct extends Product implements ILength {
constructor(public pricePerUnit : Price<Currency>, public length: Measure<"length">, public attributes : ProductAttributes = {}) {
super(pricePerUnit, attributes);
export class Product {
public id : string;
constructor(public pricePerUnit : number, public measurement : Measure<"length" | "area">, public attributes : ProductAttributes = {}) {
this.id = attributes.id || uuid.v4().toString();
}
public priceFor(length : Measure<"length">): Price<Currency> {
const ratio = length.convertTo(this.length.unit).divideBy(this.length).value;
return {
value: this.pricePerUnit.value * ratio,
};
}
}
export class AreaProduct extends Product implements IArea {
constructor(public pricePerUnit : Price<Currency>, public area : Measure<"area">, public attributes : ProductAttributes = {}) {
super(pricePerUnit, attributes);
public priceFor(measurement : Measure<"length" | "area">): number {
const ratio = measurement.convertTo(this.measurement.unit).divideBy(this.measurement).value;
return this.pricePerUnit * ratio
}
public priceFor(area : Measure<"area">): Price<Currency> {
const ratio = area.convertTo(this.area.unit).divideBy(this.area).value;
return {
value: this.pricePerUnit.value * ratio,
};
get isArea() {
return this.measurement.unit.dimension.length === 2;
}
get isLength() {
return this.measurement.unit.dimension.length === 1;
}
get attributesAsList() {
return Object.entries(this.attributes).map(([key, value]) => {
return {key, value}
})
}
public removeAttribute(key : string) {
delete this.attributes[key]
}
}

View File

@ -12,10 +12,13 @@
"lint": "expo lint"
},
"dependencies": {
"@babel/runtime": "^7.24.7",
"@expo/vector-icons": "^14.0.0",
"@react-native-async-storage/async-storage": "^1.23.1",
"@react-native/assets-registry": "^0.74.84",
"@react-navigation/native": "^6.0.2",
"@reduxjs/toolkit": "^2.2.5",
"@testing-library/react-native": "^12.5.1",
"enheter": "^1.0.27",
"expo": "~51.0.14",
"expo-constants": "~16.0.2",
@ -26,6 +29,7 @@
"expo-status-bar": "~1.12.1",
"expo-system-ui": "~3.0.6",
"expo-web-browser": "~13.0.3",
"interopRequireDefault": "link:@babel/runtime/helpers/interopRequireDefault",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.74.2",
@ -35,6 +39,7 @@
"react-native-screens": "3.31.1",
"react-native-uuid": "^2.0.2",
"react-native-web": "~0.19.10",
"react-redux": "^9.1.2",
"redux-remember": "^5.1.0",
"uuid": "^10.0.0"
},

172
pnpm-lock.yaml generated
View File

@ -5,18 +5,27 @@ settings:
excludeLinksFromLockfile: false
dependencies:
'@babel/runtime':
specifier: ^7.24.7
version: 7.24.7
'@expo/vector-icons':
specifier: ^14.0.0
version: 14.0.2
'@react-native-async-storage/async-storage':
specifier: ^1.23.1
version: 1.23.1(react-native@0.74.2)
'@react-native/assets-registry':
specifier: ^0.74.84
version: 0.74.84
'@react-navigation/native':
specifier: ^6.0.2
version: 6.1.17(react-native@0.74.2)(react@18.2.0)
'@reduxjs/toolkit':
specifier: ^2.2.5
version: 2.2.5(react@18.2.0)
version: 2.2.5(react-redux@9.1.2)(react@18.2.0)
'@testing-library/react-native':
specifier: ^12.5.1
version: 12.5.1(jest@29.7.0)(react-native@0.74.2)(react-test-renderer@18.2.0)(react@18.2.0)
enheter:
specifier: ^1.0.27
version: 1.0.27
@ -47,6 +56,9 @@ dependencies:
expo-web-browser:
specifier: ~13.0.3
version: 13.0.3(expo@51.0.14)
interopRequireDefault:
specifier: link:@babel/runtime/helpers/interopRequireDefault
version: link:@babel/runtime/helpers/interopRequireDefault
react:
specifier: 18.2.0
version: 18.2.0
@ -74,6 +86,9 @@ dependencies:
react-native-web:
specifier: ~0.19.10
version: 0.19.12(react-dom@18.2.0)(react@18.2.0)
react-redux:
specifier: ^9.1.2
version: 9.1.2(@types/react@18.2.79)(react@18.2.0)(redux@5.0.1)
redux-remember:
specifier: ^5.1.0
version: 5.1.0(redux@5.0.1)
@ -619,7 +634,6 @@ packages:
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.24.7
dev: true
/@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.7):
resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
@ -1699,7 +1713,6 @@ packages:
/@bcoe/v8-coverage@0.2.3:
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
dev: true
/@egjs/hammerjs@2.0.17:
resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==}
@ -2172,12 +2185,10 @@ packages:
get-package-type: 0.1.0
js-yaml: 3.14.1
resolve-from: 5.0.0
dev: true
/@istanbuljs/schema@0.1.3:
resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
engines: {node: '>=8'}
dev: true
/@jest/console@29.7.0:
resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==}
@ -2189,7 +2200,6 @@ packages:
jest-message-util: 29.7.0
jest-util: 29.7.0
slash: 3.0.0
dev: true
/@jest/core@29.7.0:
resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==}
@ -2232,7 +2242,6 @@ packages:
- babel-plugin-macros
- supports-color
- ts-node
dev: true
/@jest/create-cache-key-function@29.7.0:
resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==}
@ -2254,7 +2263,6 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
jest-get-type: 29.6.3
dev: true
/@jest/expect@29.7.0:
resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==}
@ -2264,7 +2272,6 @@ packages:
jest-snapshot: 29.7.0
transitivePeerDependencies:
- supports-color
dev: true
/@jest/fake-timers@29.7.0:
resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
@ -2287,7 +2294,6 @@ packages:
jest-mock: 29.7.0
transitivePeerDependencies:
- supports-color
dev: true
/@jest/reporters@29.7.0:
resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==}
@ -2324,7 +2330,6 @@ packages:
v8-to-istanbul: 9.3.0
transitivePeerDependencies:
- supports-color
dev: true
/@jest/schemas@29.6.3:
resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
@ -2339,7 +2344,6 @@ packages:
'@jridgewell/trace-mapping': 0.3.25
callsites: 3.1.0
graceful-fs: 4.2.11
dev: true
/@jest/test-result@29.7.0:
resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==}
@ -2349,7 +2353,6 @@ packages:
'@jest/types': 29.6.3
'@types/istanbul-lib-coverage': 2.0.6
collect-v8-coverage: 1.0.2
dev: true
/@jest/test-sequencer@29.7.0:
resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==}
@ -2359,7 +2362,6 @@ packages:
graceful-fs: 4.2.11
jest-haste-map: 29.7.0
slash: 3.0.0
dev: true
/@jest/transform@29.7.0:
resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
@ -2382,7 +2384,6 @@ packages:
write-file-atomic: 4.0.2
transitivePeerDependencies:
- supports-color
dev: true
/@jest/types@26.6.2:
resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==}
@ -2944,7 +2945,7 @@ packages:
nanoid: 3.3.7
dev: false
/@reduxjs/toolkit@2.2.5(react@18.2.0):
/@reduxjs/toolkit@2.2.5(react-redux@9.1.2)(react@18.2.0):
resolution: {integrity: sha512-aeFA/s5NCG7NoJe/MhmwREJxRkDs0ZaSqt0MxhWUrwCf1UQXpwR87RROJEql0uAkLI6U7snBOYOcKw83ew3FPg==}
peerDependencies:
react: ^16.9.0 || ^17.0.0 || ^18
@ -2957,6 +2958,7 @@ packages:
dependencies:
immer: 10.1.1
react: 18.2.0
react-redux: 9.1.2(@types/react@18.2.79)(react@18.2.0)(redux@5.0.1)
redux: 5.0.1
redux-thunk: 3.1.0(redux@5.0.1)
reselect: 5.1.1
@ -3092,6 +3094,26 @@ packages:
dependencies:
'@sinonjs/commons': 3.0.1
/@testing-library/react-native@12.5.1(jest@29.7.0)(react-native@0.74.2)(react-test-renderer@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-PApr3f6DmSJF/EIiWYZfcBzuy6w7fK8TW4a6KfQHTeAcfZ6lADtRO7R0QM5WI+b7tJ33JvIPgzCg1MiuRz4v0g==}
peerDependencies:
jest: '>=28.0.0'
react: '>=16.8.0'
react-native: '>=0.59'
react-test-renderer: '>=16.8.0'
peerDependenciesMeta:
jest:
optional: true
dependencies:
jest: 29.7.0
jest-matcher-utils: 29.7.0
pretty-format: 29.7.0
react: 18.2.0
react-native: 0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7)(@types/react@18.2.79)(react@18.2.0)
react-test-renderer: 18.2.0(react@18.2.0)
redent: 3.0.0
dev: false
/@tootallnate/once@2.0.0:
resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
engines: {node: '>= 10'}
@ -3105,26 +3127,22 @@ packages:
'@types/babel__generator': 7.6.8
'@types/babel__template': 7.4.4
'@types/babel__traverse': 7.20.6
dev: true
/@types/babel__generator@7.6.8:
resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==}
dependencies:
'@babel/types': 7.24.7
dev: true
/@types/babel__template@7.4.4:
resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
dependencies:
'@babel/parser': 7.24.7
'@babel/types': 7.24.7
dev: true
/@types/babel__traverse@7.20.6:
resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==}
dependencies:
'@babel/types': 7.24.7
dev: true
/@types/cookie@0.6.0:
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
@ -3134,7 +3152,6 @@ packages:
resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
dependencies:
'@types/node': 20.14.9
dev: true
/@types/hammerjs@2.0.45:
resolution: {integrity: sha512-qkcUlZmX6c4J8q45taBKTL3p+LbITgyx7qhlPYOdOHZB7B31K0mXbP5YA7i7SgDeEGuI9MnumiKPEMrxg8j3KQ==}
@ -3215,6 +3232,10 @@ packages:
resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
dev: true
/@types/use-sync-external-store@0.0.3:
resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==}
dev: false
/@types/yargs-parser@21.0.3:
resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
@ -3680,7 +3701,6 @@ packages:
slash: 3.0.0
transitivePeerDependencies:
- supports-color
dev: true
/babel-plugin-istanbul@6.1.1:
resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
@ -3693,7 +3713,6 @@ packages:
test-exclude: 6.0.0
transitivePeerDependencies:
- supports-color
dev: true
/babel-plugin-jest-hoist@29.6.3:
resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
@ -3703,7 +3722,6 @@ packages:
'@babel/types': 7.24.7
'@types/babel__core': 7.20.5
'@types/babel__traverse': 7.20.6
dev: true
/babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.7):
resolution: {integrity: sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==}
@ -3788,7 +3806,6 @@ packages:
'@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7)
'@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7)
'@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.7)
dev: true
/babel-preset-expo@11.0.10(@babel/core@7.24.7)(@babel/preset-env@7.24.7):
resolution: {integrity: sha512-YBg40Om31gw9IPlRw5v8elzgtPUtNEh4GSibBi5MsmmYddGg4VPjWtCZIFJChN543qRmbGb/fa/kejvLX567hQ==}
@ -3817,7 +3834,6 @@ packages:
'@babel/core': 7.24.7
babel-plugin-jest-hoist: 29.6.3
babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.7)
dev: true
/babel-runtime@6.26.0:
resolution: {integrity: sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==}
@ -4003,7 +4019,6 @@ packages:
/callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
dev: true
/camelcase@5.3.1:
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
@ -4042,7 +4057,6 @@ packages:
/char-regex@1.0.2:
resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
engines: {node: '>=10'}
dev: true
/char-regex@2.0.1:
resolution: {integrity: sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==}
@ -4105,7 +4119,6 @@ packages:
/cjs-module-lexer@1.3.1:
resolution: {integrity: sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==}
dev: true
/clean-stack@2.2.0:
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
@ -4169,11 +4182,9 @@ packages:
/co@4.6.0:
resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
dev: true
/collect-v8-coverage@1.0.2:
resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==}
dev: true
/color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
@ -4343,7 +4354,6 @@ packages:
- babel-plugin-macros
- supports-color
- ts-node
dev: true
/cross-fetch@3.1.8:
resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==}
@ -4528,7 +4538,6 @@ packages:
peerDependenciesMeta:
babel-plugin-macros:
optional: true
dev: true
/deep-equal@2.2.3:
resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==}
@ -4643,12 +4652,10 @@ packages:
/detect-newline@3.1.0:
resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
engines: {node: '>=8'}
dev: true
/diff-sequences@29.6.3:
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dev: true
/dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
@ -4736,7 +4743,6 @@ packages:
/emittery@0.13.1:
resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
engines: {node: '>=12'}
dev: true
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@ -5333,7 +5339,6 @@ packages:
/exit@0.1.2:
resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
engines: {node: '>= 0.8.0'}
dev: true
/expect@29.7.0:
resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
@ -5344,7 +5349,6 @@ packages:
jest-matcher-utils: 29.7.0
jest-message-util: 29.7.0
jest-util: 29.7.0
dev: true
/expo-asset@10.0.9(expo@51.0.14):
resolution: {integrity: sha512-KX7LPtVf9eeMidUvYZafXZldrVdzfjZNKKFAjFvDy2twg7sTa2R0L4VdCXp32eGLWZyk+i/rpOUSbyD1YFyJnA==}
@ -5549,7 +5553,6 @@ packages:
/fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
dev: true
/fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
@ -5831,7 +5834,6 @@ packages:
/get-package-type@0.1.0:
resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
engines: {node: '>=8.0.0'}
dev: true
/get-port@3.2.0:
resolution: {integrity: sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==}
@ -6077,7 +6079,6 @@ packages:
/html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
dev: true
/htmlparser2@8.0.2:
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
@ -6177,7 +6178,6 @@ packages:
dependencies:
pkg-dir: 4.2.0
resolve-cwd: 3.0.0
dev: true
/imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
@ -6345,7 +6345,6 @@ packages:
/is-generator-fn@2.1.0:
resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
engines: {node: '>=6'}
dev: true
/is-generator-function@1.0.10:
resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
@ -6531,7 +6530,6 @@ packages:
/istanbul-lib-coverage@3.2.2:
resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
engines: {node: '>=8'}
dev: true
/istanbul-lib-instrument@5.2.1:
resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}
@ -6544,7 +6542,6 @@ packages:
semver: 6.3.1
transitivePeerDependencies:
- supports-color
dev: true
/istanbul-lib-instrument@6.0.2:
resolution: {integrity: sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==}
@ -6557,7 +6554,6 @@ packages:
semver: 7.6.2
transitivePeerDependencies:
- supports-color
dev: true
/istanbul-lib-report@3.0.1:
resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
@ -6566,7 +6562,6 @@ packages:
istanbul-lib-coverage: 3.2.2
make-dir: 4.0.0
supports-color: 7.2.0
dev: true
/istanbul-lib-source-maps@4.0.1:
resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
@ -6577,7 +6572,6 @@ packages:
source-map: 0.6.1
transitivePeerDependencies:
- supports-color
dev: true
/istanbul-reports@3.1.7:
resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
@ -6585,7 +6579,6 @@ packages:
dependencies:
html-escaper: 2.0.2
istanbul-lib-report: 3.0.1
dev: true
/iterator.prototype@1.1.2:
resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==}
@ -6613,7 +6606,6 @@ packages:
execa: 5.1.1
jest-util: 29.7.0
p-limit: 3.1.0
dev: true
/jest-circus@29.7.0:
resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==}
@ -6642,7 +6634,6 @@ packages:
transitivePeerDependencies:
- babel-plugin-macros
- supports-color
dev: true
/jest-cli@29.7.0:
resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
@ -6670,7 +6661,6 @@ packages:
- babel-plugin-macros
- supports-color
- ts-node
dev: true
/jest-config@29.7.0(@types/node@20.14.9):
resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
@ -6710,7 +6700,6 @@ packages:
transitivePeerDependencies:
- babel-plugin-macros
- supports-color
dev: true
/jest-diff@29.7.0:
resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
@ -6720,14 +6709,12 @@ packages:
diff-sequences: 29.6.3
jest-get-type: 29.6.3
pretty-format: 29.7.0
dev: true
/jest-docblock@29.7.0:
resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
detect-newline: 3.1.0
dev: true
/jest-each@29.7.0:
resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
@ -6738,7 +6725,6 @@ packages:
jest-get-type: 29.6.3
jest-util: 29.7.0
pretty-format: 29.7.0
dev: true
/jest-environment-jsdom@29.7.0:
resolution: {integrity: sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==}
@ -6821,7 +6807,6 @@ packages:
walker: 1.0.8
optionalDependencies:
fsevents: 2.3.3
dev: true
/jest-leak-detector@29.7.0:
resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==}
@ -6829,7 +6814,6 @@ packages:
dependencies:
jest-get-type: 29.6.3
pretty-format: 29.7.0
dev: true
/jest-matcher-utils@29.7.0:
resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
@ -6839,7 +6823,6 @@ packages:
jest-diff: 29.7.0
jest-get-type: 29.6.3
pretty-format: 29.7.0
dev: true
/jest-message-util@29.7.0:
resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
@ -6873,12 +6856,10 @@ packages:
optional: true
dependencies:
jest-resolve: 29.7.0
dev: true
/jest-regex-util@29.6.3:
resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dev: true
/jest-resolve-dependencies@29.7.0:
resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==}
@ -6888,7 +6869,6 @@ packages:
jest-snapshot: 29.7.0
transitivePeerDependencies:
- supports-color
dev: true
/jest-resolve@29.7.0:
resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==}
@ -6903,7 +6883,6 @@ packages:
resolve: 1.22.8
resolve.exports: 2.0.2
slash: 3.0.0
dev: true
/jest-runner@29.7.0:
resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==}
@ -6932,7 +6911,6 @@ packages:
source-map-support: 0.5.13
transitivePeerDependencies:
- supports-color
dev: true
/jest-runtime@29.7.0:
resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==}
@ -6962,7 +6940,6 @@ packages:
strip-bom: 4.0.0
transitivePeerDependencies:
- supports-color
dev: true
/jest-snapshot@29.7.0:
resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
@ -6990,7 +6967,6 @@ packages:
semver: 7.6.2
transitivePeerDependencies:
- supports-color
dev: true
/jest-util@29.7.0:
resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
@ -7050,7 +7026,6 @@ packages:
emittery: 0.13.1
jest-util: 29.7.0
string-length: 4.0.2
dev: true
/jest-worker@29.7.0:
resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
@ -7080,7 +7055,6 @@ packages:
- babel-plugin-macros
- supports-color
- ts-node
dev: true
/jimp-compact@0.16.1:
resolution: {integrity: sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==}
@ -7215,7 +7189,6 @@ packages:
/json-parse-even-better-errors@2.3.1:
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
dev: true
/json-schema-deref-sync@0.13.0:
resolution: {integrity: sha512-YBOEogm5w9Op337yb6pAT6ZXDqlxAsQCanM3grid8lMWNxRJO/zWEJi3ZzqDL8boWfwhTFym5EFrNgWwpqcBRg==}
@ -7528,7 +7501,6 @@ packages:
engines: {node: '>=10'}
dependencies:
semver: 7.6.2
dev: true
/make-error@1.3.6:
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
@ -7847,6 +7819,11 @@ packages:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
/min-indent@1.0.1:
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
engines: {node: '>=4'}
dev: false
/minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
@ -7966,7 +7943,6 @@ packages:
/natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: true
/ncp@2.0.0:
resolution: {integrity: sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==}
@ -8358,7 +8334,6 @@ packages:
error-ex: 1.3.2
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
dev: true
/parse-png@2.1.0:
resolution: {integrity: sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==}
@ -8467,7 +8442,6 @@ packages:
engines: {node: '>=8'}
dependencies:
find-up: 4.1.0
dev: true
/plist@3.1.0:
resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==}
@ -8590,7 +8564,6 @@ packages:
/pure-rand@6.1.0:
resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
dev: true
/qrcode-terminal@0.11.0:
resolution: {integrity: sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==}
@ -8854,6 +8827,25 @@ packages:
- utf-8-validate
dev: false
/react-redux@9.1.2(@types/react@18.2.79)(react@18.2.0)(redux@5.0.1):
resolution: {integrity: sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==}
peerDependencies:
'@types/react': ^18.2.25
react: ^18.0
redux: ^5.0.0
peerDependenciesMeta:
'@types/react':
optional: true
redux:
optional: true
dependencies:
'@types/react': 18.2.79
'@types/use-sync-external-store': 0.0.3
react: 18.2.0
redux: 5.0.1
use-sync-external-store: 1.2.2(react@18.2.0)
dev: false
/react-refresh@0.14.2:
resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
engines: {node: '>=0.10.0'}
@ -8877,7 +8869,6 @@ packages:
react-is: 18.3.1
react-shallow-renderer: 16.15.0(react@18.2.0)
scheduler: 0.23.2
dev: true
/react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
@ -8920,6 +8911,14 @@ packages:
tslib: 2.6.3
dev: false
/redent@3.0.0:
resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
engines: {node: '>=8'}
dependencies:
indent-string: 4.0.0
strip-indent: 3.0.0
dev: false
/redux-remember@5.1.0(redux@5.0.1):
resolution: {integrity: sha512-Z6/S/brpwflOsGpX8Az93eujJ5fytMcaefxDfx0iib5d0DkL804zlw/Fhh/4HzZ5nXsP67j1zPUeDNWO1rhfvA==}
peerDependencies:
@ -9058,7 +9057,6 @@ packages:
engines: {node: '>=8'}
dependencies:
resolve-from: 5.0.0
dev: true
/resolve-from@3.0.0:
resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==}
@ -9435,7 +9433,6 @@ packages:
dependencies:
buffer-from: 1.1.2
source-map: 0.6.1
dev: true
/source-map-support@0.5.21:
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
@ -9557,7 +9554,6 @@ packages:
dependencies:
char-regex: 1.0.2
strip-ansi: 6.0.1
dev: true
/string-length@5.0.1:
resolution: {integrity: sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==}
@ -9672,7 +9668,6 @@ packages:
/strip-bom@4.0.0:
resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
engines: {node: '>=8'}
dev: true
/strip-eof@1.0.0:
resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==}
@ -9683,6 +9678,13 @@ packages:
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
engines: {node: '>=6'}
/strip-indent@3.0.0:
resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
engines: {node: '>=8'}
dependencies:
min-indent: 1.0.1
dev: false
/strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
@ -9691,7 +9693,6 @@ packages:
/strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
dev: true
/strnum@1.0.5:
resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
@ -9839,7 +9840,6 @@ packages:
'@istanbuljs/schema': 0.1.3
glob: 7.2.3
minimatch: 3.1.2
dev: true
/text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
@ -10204,6 +10204,14 @@ packages:
react: 18.2.0
dev: false
/use-sync-external-store@1.2.2(react@18.2.0):
resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
react: 18.2.0
dev: false
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: false
@ -10244,7 +10252,6 @@ packages:
'@jridgewell/trace-mapping': 0.3.25
'@types/istanbul-lib-coverage': 2.0.6
convert-source-map: 2.0.0
dev: true
/valid-url@1.0.9:
resolution: {integrity: sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA==}
@ -10470,7 +10477,6 @@ packages:
dependencies:
imurmurhash: 0.1.4
signal-exit: 3.0.7
dev: true
/ws@6.2.3:
resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==}

View File

@ -1,6 +1,7 @@
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"jsx": "react",
"strict": true,
"paths": {
"@/*": [