native-pytech 1.0.1 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -6
- package/dist/app/editPage.d.ts +1 -0
- package/dist/app/editPage.js +1 -0
- package/dist/libs/editPage/index.d.ts +7 -0
- package/dist/libs/editPage/index.js +5 -0
- package/dist/libs/editPage/src/components/Item/index.d.ts +4 -0
- package/dist/libs/editPage/src/components/Item/index.js +12 -0
- package/dist/libs/editPage/src/components/Item/types.d.ts +15 -0
- package/dist/libs/editPage/src/components/Item/types.js +1 -0
- package/dist/libs/editPage/src/components/Page/index.d.ts +5 -0
- package/dist/libs/editPage/src/components/Page/index.js +84 -0
- package/dist/libs/editPage/src/components/Page/types.d.ts +26 -0
- package/dist/libs/editPage/src/components/Page/types.js +1 -0
- package/dist/libs/editPage/src/components/TextField/index.d.ts +4 -0
- package/dist/libs/editPage/src/components/TextField/index.js +55 -0
- package/dist/libs/editPage/src/components/TextField/types.d.ts +29 -0
- package/dist/libs/editPage/src/components/TextField/types.js +1 -0
- package/dist/libs/editPage/src/context/item.d.ts +7 -0
- package/dist/libs/editPage/src/context/item.js +2 -0
- package/dist/libs/editPage/src/context/page.d.ts +18 -0
- package/dist/libs/editPage/src/context/page.js +2 -0
- package/dist/libs/login/src/Pages/utils.d.ts +1 -1
- package/dist/libs/login/src/Pages/utils.js +17 -10
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -8,23 +8,59 @@ Librería de componentes y utilidades para apps **React Native** / **Expo** (Pyt
|
|
|
8
8
|
npm install native-pytech
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
Para mantener actualizado:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx expo install native-pytech@latest
|
|
15
|
+
```
|
|
16
|
+
|
|
11
17
|
Instalá también las **peer dependencies** que use tu app (Expo, React Native, etc.). Revisá la sección `peerDependencies` en el `package.json` del paquete o de este repo.
|
|
12
18
|
|
|
13
19
|
## Uso
|
|
14
20
|
|
|
15
|
-
Entrada principal (reexporta los módulos públicos):
|
|
16
|
-
|
|
17
21
|
```ts
|
|
18
|
-
import { ... } from 'native-pytech'
|
|
22
|
+
import { ... } from 'native-pytech/{submodulo}'
|
|
19
23
|
```
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
Ejemplos:
|
|
22
26
|
|
|
23
27
|
```ts
|
|
24
|
-
import { ... } from 'native-pytech/login'
|
|
25
|
-
import { ... } from 'native-pytech/
|
|
28
|
+
import Login, { ... } from 'native-pytech/login'
|
|
29
|
+
import Table, { ... } from 'native-pytech/table'
|
|
26
30
|
```
|
|
27
31
|
|
|
32
|
+
# Rutas disponibles
|
|
33
|
+
|
|
34
|
+
- `/assets`
|
|
35
|
+
- `/components`
|
|
36
|
+
- `/RemoveCircle`
|
|
37
|
+
- `/ReorderThreeOutline`
|
|
38
|
+
- `/images`
|
|
39
|
+
- `/ionicons`
|
|
40
|
+
- `/components`
|
|
41
|
+
- `/Gradient`
|
|
42
|
+
- `/CloseButton`
|
|
43
|
+
- `/Link`
|
|
44
|
+
- `/Text`
|
|
45
|
+
- `/Theme`
|
|
46
|
+
- `/constants`
|
|
47
|
+
- `/colors`
|
|
48
|
+
- `/consts`
|
|
49
|
+
- `/handleFontObserver`
|
|
50
|
+
- `/hooks`
|
|
51
|
+
- `/utils`
|
|
52
|
+
- `/editPage`
|
|
53
|
+
- `/footer`
|
|
54
|
+
- `/login`
|
|
55
|
+
- `/page`
|
|
56
|
+
- `/providers`
|
|
57
|
+
- `/app`
|
|
58
|
+
- `/segmentedControl`
|
|
59
|
+
- `/sql`
|
|
60
|
+
- `/supabase`
|
|
61
|
+
- `/swiftui`
|
|
62
|
+
- `/table`
|
|
63
|
+
|
|
28
64
|
## Licencia
|
|
29
65
|
|
|
30
66
|
MIT — ver `LICENSE`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../libs/editPage';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../libs/editPage';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { HStack, Spacer, Text } from '@expo/ui/swift-ui';
|
|
2
|
+
import React, { memo } from 'react';
|
|
3
|
+
import TextField from '../TextField';
|
|
4
|
+
export default memo(({ label, minLengthSpacer, ...textFieldProps }) => {
|
|
5
|
+
if (!label)
|
|
6
|
+
return <TextField {...textFieldProps}/>;
|
|
7
|
+
return (<HStack>
|
|
8
|
+
<Text>{label}</Text>
|
|
9
|
+
<Spacer minLength={minLengthSpacer}/>
|
|
10
|
+
<TextField {...textFieldProps}/>
|
|
11
|
+
</HStack>);
|
|
12
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type SpacerProps } from "@expo/ui/swift-ui";
|
|
2
|
+
import type TextFieldProps from '../TextField/types';
|
|
3
|
+
type Props = TextFieldProps & {
|
|
4
|
+
/**
|
|
5
|
+
Text to display on the left of the text field.
|
|
6
|
+
If not provided, the item will be only a text field.
|
|
7
|
+
*/
|
|
8
|
+
label?: string;
|
|
9
|
+
/**
|
|
10
|
+
Minimum length of the spacer between the title and the text field.
|
|
11
|
+
If the title is not provided, will not be displayed.
|
|
12
|
+
*/
|
|
13
|
+
minLengthSpacer?: SpacerProps['minLength'];
|
|
14
|
+
};
|
|
15
|
+
export default Props;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Host, List, Section } from '@expo/ui/swift-ui';
|
|
2
|
+
import { useObservable, useValue } from '@legendapp/state/react';
|
|
3
|
+
import { Stack, useRouter } from 'expo-router';
|
|
4
|
+
import React, { memo, useCallback, useMemo, useRef } from 'react';
|
|
5
|
+
import { useEffectWithoutFirstRender } from '../../../../../libs/constants/hooks';
|
|
6
|
+
import { Provider } from '../../context/page';
|
|
7
|
+
import { Provider as ItemProvider } from '../../context/item';
|
|
8
|
+
function Component({ data = [], renderItem, onSave, }) {
|
|
9
|
+
// ------------------- Variables -------------------
|
|
10
|
+
const router = useRouter();
|
|
11
|
+
const saveEnabledRef = useRef(false);
|
|
12
|
+
const values = (data ?? []).reduce((acc, item, index) => {
|
|
13
|
+
acc[index] = {
|
|
14
|
+
value: undefined,
|
|
15
|
+
hasChanged: false,
|
|
16
|
+
isValid: true,
|
|
17
|
+
};
|
|
18
|
+
return acc;
|
|
19
|
+
}, {});
|
|
20
|
+
const store = useObservable({
|
|
21
|
+
values: values,
|
|
22
|
+
saveEnabled: (() => {
|
|
23
|
+
const values = store.values.get();
|
|
24
|
+
const listValues = Object.values(values);
|
|
25
|
+
const hasChanged = listValues.some(value => value.hasChanged);
|
|
26
|
+
const allValid = listValues.every(value => value.isValid);
|
|
27
|
+
return hasChanged && allValid;
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
const saveEnabled = useValue(() => store.saveEnabled.get());
|
|
31
|
+
useEffectWithoutFirstRender(() => {
|
|
32
|
+
saveEnabledRef.current = saveEnabled;
|
|
33
|
+
}, [saveEnabled]);
|
|
34
|
+
const textFieldsRefs = useRef({});
|
|
35
|
+
// ------------------- Functions -------------------
|
|
36
|
+
const onPressSave = useCallback(async () => {
|
|
37
|
+
// Obtengo los valores del store
|
|
38
|
+
const values = store.values.peek();
|
|
39
|
+
const valuesToSave = Object.values(values).map(value => value.value ?? null);
|
|
40
|
+
// Llamo a la función onSave
|
|
41
|
+
const result = await onSave?.(valuesToSave);
|
|
42
|
+
if (result === false)
|
|
43
|
+
return;
|
|
44
|
+
router.back();
|
|
45
|
+
}, [onSave, store.values]);
|
|
46
|
+
// ------------------- Provider -------------------
|
|
47
|
+
const value = useMemo(() => ({
|
|
48
|
+
store,
|
|
49
|
+
saveEnabledRef,
|
|
50
|
+
onPressSave,
|
|
51
|
+
isUniqueItem: (data?.length ?? 0) === 1,
|
|
52
|
+
textFieldsRefs
|
|
53
|
+
}), []);
|
|
54
|
+
return (<>
|
|
55
|
+
<Stack.Toolbar placement="left">
|
|
56
|
+
<Stack.Toolbar.Button onPress={() => router.back()}>
|
|
57
|
+
<Stack.Toolbar.Icon sf="xmark"/>
|
|
58
|
+
</Stack.Toolbar.Button>
|
|
59
|
+
</Stack.Toolbar>
|
|
60
|
+
|
|
61
|
+
<Stack.Toolbar placement="right">
|
|
62
|
+
<Stack.Toolbar.Button disabled={!saveEnabled} variant="done" onPress={onPressSave}>
|
|
63
|
+
<Stack.Toolbar.Icon sf="checkmark"/>
|
|
64
|
+
</Stack.Toolbar.Button>
|
|
65
|
+
</Stack.Toolbar>
|
|
66
|
+
|
|
67
|
+
<Host style={{ flex: 1 }}>
|
|
68
|
+
<List>
|
|
69
|
+
<Section>
|
|
70
|
+
<Provider value={value}>
|
|
71
|
+
{data.map((item, index) => {
|
|
72
|
+
const nextIndex = index + 1;
|
|
73
|
+
const value = { index, nextIndex: nextIndex < data.length ? nextIndex : undefined };
|
|
74
|
+
return (<ItemProvider key={index} value={value}>
|
|
75
|
+
{renderItem?.(item)}
|
|
76
|
+
</ItemProvider>);
|
|
77
|
+
})}
|
|
78
|
+
</Provider>
|
|
79
|
+
</Section>
|
|
80
|
+
</List>
|
|
81
|
+
</Host>
|
|
82
|
+
</>);
|
|
83
|
+
}
|
|
84
|
+
export default memo(Component);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type Props<T> = {
|
|
2
|
+
/**
|
|
3
|
+
The data items to be rendered inside the list.
|
|
4
|
+
@default []
|
|
5
|
+
*/
|
|
6
|
+
data?: T[];
|
|
7
|
+
/**
|
|
8
|
+
The function to render the item.
|
|
9
|
+
*/
|
|
10
|
+
renderItem?: (item: T) => React.ReactNode;
|
|
11
|
+
/**
|
|
12
|
+
Function to be called when the user saves the changes.
|
|
13
|
+
If the function returns true, the user will be redirected to the previous screen.
|
|
14
|
+
*/
|
|
15
|
+
onSave?: (values: (string | null)[]) => boolean | Promise<boolean>;
|
|
16
|
+
};
|
|
17
|
+
export type Values = Record<number, {
|
|
18
|
+
value: string | null | undefined;
|
|
19
|
+
hasChanged: boolean;
|
|
20
|
+
isValid: boolean;
|
|
21
|
+
}>;
|
|
22
|
+
export type Store = {
|
|
23
|
+
values: Values;
|
|
24
|
+
saveEnabled: boolean;
|
|
25
|
+
};
|
|
26
|
+
export default Props;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React, { useMemo, memo, useRef, useCallback, useEffect } from "react";
|
|
2
|
+
import { SecureField, TextField } from "@expo/ui/swift-ui";
|
|
3
|
+
import { keyboardType as keyboardTypeModifier, submitLabel, textInputAutocapitalization, onSubmit } from '@expo/ui/swift-ui/modifiers';
|
|
4
|
+
import { usePage } from '../../context/page';
|
|
5
|
+
import { useItem } from '../../context/item';
|
|
6
|
+
export default memo(({ defaultValue, placeholder, keyboardType, autocapitalization = true, secureTextEntry, isValid, }) => {
|
|
7
|
+
// ------------------- Variables -------------------
|
|
8
|
+
const { store, isUniqueItem, saveEnabledRef, onPressSave, textFieldsRefs } = usePage();
|
|
9
|
+
const { index, nextIndex } = useItem();
|
|
10
|
+
const ref = useRef(null);
|
|
11
|
+
textFieldsRefs.current[index] = ref;
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
store.values[index].value.set(defaultValue);
|
|
14
|
+
}, [defaultValue]);
|
|
15
|
+
// -------------------- Functions --------------------
|
|
16
|
+
const onValueChange = useCallback((value) => {
|
|
17
|
+
const _value = value.trim() === '' ? null : value.trim();
|
|
18
|
+
store.values[index].set({
|
|
19
|
+
value: _value,
|
|
20
|
+
hasChanged: _value !== defaultValue,
|
|
21
|
+
isValid: isValid?.(_value) ?? true,
|
|
22
|
+
});
|
|
23
|
+
}, []);
|
|
24
|
+
const _onSubmit = useCallback(() => {
|
|
25
|
+
// Guarda los cambios
|
|
26
|
+
if (isUniqueItem) {
|
|
27
|
+
const saveEnabled = saveEnabledRef.current;
|
|
28
|
+
if (!saveEnabled)
|
|
29
|
+
return;
|
|
30
|
+
onPressSave();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// Va al siguiente campo
|
|
34
|
+
if (!nextIndex)
|
|
35
|
+
return;
|
|
36
|
+
textFieldsRefs.current[nextIndex].current?.focus();
|
|
37
|
+
}, []);
|
|
38
|
+
// -------------------- Props --------------------
|
|
39
|
+
const modifiers = useMemo(() => [
|
|
40
|
+
...(isUniqueItem ? [submitLabel('done')] : []),
|
|
41
|
+
...(keyboardType ? [keyboardTypeModifier(keyboardType)] : []),
|
|
42
|
+
...(!autocapitalization ? [textInputAutocapitalization('never')] : []),
|
|
43
|
+
onSubmit(_onSubmit),
|
|
44
|
+
], [keyboardType, autocapitalization, isUniqueItem]);
|
|
45
|
+
const props = useMemo(() => ({
|
|
46
|
+
autoFocus: isUniqueItem,
|
|
47
|
+
modifiers,
|
|
48
|
+
placeholder,
|
|
49
|
+
defaultValue,
|
|
50
|
+
onValueChange,
|
|
51
|
+
}), [modifiers, placeholder, defaultValue]);
|
|
52
|
+
if (secureTextEntry)
|
|
53
|
+
return <SecureField {...props} ref={ref}/>;
|
|
54
|
+
return <TextField {...props} ref={ref}/>;
|
|
55
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { keyboardType } from "@expo/ui/swift-ui/modifiers";
|
|
2
|
+
type Props = {
|
|
3
|
+
/**
|
|
4
|
+
Default value of the text field.
|
|
5
|
+
*/
|
|
6
|
+
defaultValue?: string;
|
|
7
|
+
/**
|
|
8
|
+
Placeholder of the text field.
|
|
9
|
+
*/
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
/**
|
|
12
|
+
Keyboard type. Uses the keyboardType modifier.
|
|
13
|
+
*/
|
|
14
|
+
keyboardType?: Parameters<typeof keyboardType>[0];
|
|
15
|
+
/**
|
|
16
|
+
If true, the text field will be autocapitalized. Uses the textInputAutocapitalization modifier.
|
|
17
|
+
@default true
|
|
18
|
+
*/
|
|
19
|
+
autocapitalization?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
If true, the text field will be secure (password).
|
|
22
|
+
*/
|
|
23
|
+
secureTextEntry?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
Function to validate the value.
|
|
26
|
+
*/
|
|
27
|
+
isValid?: (value: string | null) => boolean;
|
|
28
|
+
};
|
|
29
|
+
export default Props;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Observable } from '@legendapp/state';
|
|
2
|
+
import { TextFieldRef } from '@expo/ui/swift-ui';
|
|
3
|
+
import type { RefObject } from 'react';
|
|
4
|
+
import type { Store } from '../components/Page/types';
|
|
5
|
+
export type TextFieldsRefsType = Record<number, RefObject<TextFieldRef | null>>;
|
|
6
|
+
export declare const Provider: import("react").Provider<{
|
|
7
|
+
store: Observable<Store>;
|
|
8
|
+
saveEnabledRef: RefObject<boolean>;
|
|
9
|
+
onPressSave: () => Promise<void>;
|
|
10
|
+
isUniqueItem: boolean;
|
|
11
|
+
textFieldsRefs: RefObject<TextFieldsRefsType>;
|
|
12
|
+
}>, usePage: () => {
|
|
13
|
+
store: Observable<Store>;
|
|
14
|
+
saveEnabledRef: RefObject<boolean>;
|
|
15
|
+
onPressSave: () => Promise<void>;
|
|
16
|
+
isUniqueItem: boolean;
|
|
17
|
+
textFieldsRefs: RefObject<TextFieldsRefsType>;
|
|
18
|
+
};
|
|
@@ -18,22 +18,29 @@ export const getAbbreviatedName = ({ first_name, last_name, mail }) => {
|
|
|
18
18
|
return name.toUpperCase();
|
|
19
19
|
};
|
|
20
20
|
export const handleSubmitLogIn = async ({ username, router }) => {
|
|
21
|
-
username = username.trim()
|
|
22
|
-
const mail = username.includes('@') ? username : `${username}@pytech.com
|
|
21
|
+
/*username = username.trim()
|
|
22
|
+
const mail = username.includes('@') ? username : `${username}@pytech.com`
|
|
23
|
+
|
|
23
24
|
// Obtengo el user_id
|
|
24
|
-
const { data: dataUsers, error: errorUsers } = await supabase.client.schema('admin').from('users').select('id').eq('mail', mail)
|
|
25
|
-
if (errorUsers)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return { succeded: false, message: 'Revisa la información de la cuenta que ingresaste y vuelve a intentarlo.' };
|
|
25
|
+
const { data: dataUsers, error: errorUsers } = await supabase.client.schema('admin').from('users').select('id').eq('mail', mail)
|
|
26
|
+
if (errorUsers) return {succeded: false, message: errorUsers.message}
|
|
27
|
+
if (dataUsers.length === 0) return {succeded: false, message: 'Revisa la información de la cuenta que ingresaste y vuelve a intentarlo.'}
|
|
28
|
+
|
|
29
29
|
// Obtengo los datos del perfil
|
|
30
|
-
const { data, error } = await supabase.client.schema('admin').from('profiles').select('first_name,second_name,last_name,color').eq('user_id', dataUsers[0].id)
|
|
30
|
+
const { data, error } = await supabase.client.schema('admin').from('profiles').select('first_name,second_name,last_name,color').eq('user_id', dataUsers[0].id)
|
|
31
|
+
if (error) return {succeded: false, message: error.message}
|
|
32
|
+
if (data.length === 0) return {succeded: false, message: 'Revisa la información de la cuenta que ingresaste y vuelve a intentarlo.'}*/
|
|
33
|
+
const { data, error } = await supabase.execFunction({
|
|
34
|
+
name: 'login',
|
|
35
|
+
args: { p_identifier: username }
|
|
36
|
+
});
|
|
37
|
+
console.log('login', data);
|
|
31
38
|
if (error)
|
|
32
39
|
return { succeded: false, message: error.message };
|
|
33
|
-
if (data
|
|
40
|
+
if (!data)
|
|
34
41
|
return { succeded: false, message: 'Revisa la información de la cuenta que ingresaste y vuelve a intentarlo.' };
|
|
35
42
|
// Success
|
|
36
|
-
router.push({ pathname: '/login/inicio/perfil', params: { ...data
|
|
43
|
+
router.push({ pathname: '/login/inicio/perfil', params: { ...data, user_id: data.user_id, mail: data.email } });
|
|
37
44
|
return { succeded: true, message: '' };
|
|
38
45
|
};
|
|
39
46
|
export const handleSubmitLogInPerfil = async ({ mail, password }) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "native-pytech",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Libreria de React Native Pytech",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "node scripts/build.js",
|
|
11
11
|
"typecheck": "tsc --noEmit",
|
|
12
|
-
"prepublishOnly": "npm run build"
|
|
12
|
+
"prepublishOnly": "npm run build",
|
|
13
|
+
"release": "npm version patch && npm publish"
|
|
13
14
|
},
|
|
14
15
|
"files": [
|
|
15
16
|
"dist",
|