attempt to fix unit tests.
This commit is contained in:
parent
4561cfacd4
commit
562cae7f5a
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"jest.jestCommandLine": "node_modules/.bin/jest",
|
||||
}
|
@ -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} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
|
@ -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,
|
||||
},
|
||||
});
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
37
app/(tabs)/product-editor.tsx
Normal file
37
app/(tabs)/product-editor.tsx
Normal 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',
|
||||
},
|
||||
});
|
@ -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>();
|
@ -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 (
|
||||
|
45
components/ProductAttributeEditor.tsx
Normal file
45
components/ProductAttributeEditor.tsx
Normal 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({
|
||||
|
||||
});
|
47
components/ProductEditor.tsx
Normal file
47
components/ProductEditor.tsx
Normal 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: {
|
||||
|
||||
}
|
||||
})
|
58
components/ProductEditorItem.tsx
Normal file
58
components/ProductEditorItem.tsx
Normal 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: {},
|
||||
})
|
44
components/ProductTile.tsx
Normal file
44
components/ProductTile.tsx
Normal 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: {
|
||||
|
||||
},
|
||||
})
|
27
components/__tests__/ProductAttributeEditor-test.tsx
Normal file
27
components/__tests__/ProductAttributeEditor-test.tsx
Normal 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();
|
||||
|
||||
})
|
||||
})
|
41
components/__tests__/util.tsx
Normal file
41
components/__tests__/util.tsx
Normal 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 })
|
||||
};
|
||||
}
|
||||
|
11
features/product/initialProducts.ts
Normal file
11
features/product/initialProducts.ts
Normal 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"}),
|
||||
]
|
@ -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)"
|
||||
]
|
||||
};
|
@ -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);
|
||||
});
|
||||
|
||||
});
|
@ -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>;
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
interface ILength {
|
||||
length : Measure<"length">
|
||||
public priceFor(measurement : Measure<"length" | "area">): number {
|
||||
const ratio = measurement.convertTo(this.measurement.unit).divideBy(this.measurement).value;
|
||||
return this.pricePerUnit * ratio
|
||||
}
|
||||
|
||||
interface IArea {
|
||||
area: Measure<"area">
|
||||
get isArea() {
|
||||
return this.measurement.unit.dimension.length === 2;
|
||||
}
|
||||
|
||||
export class LengthProduct extends Product implements ILength {
|
||||
constructor(public pricePerUnit : Price<Currency>, public length: Measure<"length">, public attributes : ProductAttributes = {}) {
|
||||
super(pricePerUnit, attributes);
|
||||
get isLength() {
|
||||
return this.measurement.unit.dimension.length === 1;
|
||||
}
|
||||
|
||||
public priceFor(length : Measure<"length">): Price<Currency> {
|
||||
const ratio = length.convertTo(this.length.unit).divideBy(this.length).value;
|
||||
return {
|
||||
value: this.pricePerUnit.value * ratio,
|
||||
};
|
||||
}
|
||||
get attributesAsList() {
|
||||
return Object.entries(this.attributes).map(([key, value]) => {
|
||||
return {key, value}
|
||||
})
|
||||
}
|
||||
|
||||
export class AreaProduct extends Product implements IArea {
|
||||
constructor(public pricePerUnit : Price<Currency>, public area : Measure<"area">, public attributes : ProductAttributes = {}) {
|
||||
super(pricePerUnit, attributes);
|
||||
}
|
||||
|
||||
public priceFor(area : Measure<"area">): Price<Currency> {
|
||||
const ratio = area.convertTo(this.area.unit).divideBy(this.area).value;
|
||||
return {
|
||||
value: this.pricePerUnit.value * ratio,
|
||||
};
|
||||
public removeAttribute(key : string) {
|
||||
delete this.attributes[key]
|
||||
}
|
||||
}
|
@ -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
172
pnpm-lock.yaml
@ -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==}
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"extends": "expo/tsconfig.base",
|
||||
"compilerOptions": {
|
||||
"jsx": "react",
|
||||
"strict": true,
|
||||
"paths": {
|
||||
"@/*": [
|
||||
|
Loading…
Reference in New Issue
Block a user