cdslibrary 1.0.0
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/.expo/README.md +8 -0
- package/.expo/devices.json +3 -0
- package/.expo/packager-info.json +4 -0
- package/.expo/settings.json +10 -0
- package/.expo/web/cache/production/images/favicon/favicon-24272cdaeff82cc5facdaccd982a6f05b60c4504704bbf94c19a6388659880bb-contain-transparent/favicon-48.png +0 -0
- package/app.json +23 -0
- package/assets/adaptive-icon.png +0 -0
- package/assets/favicon.png +0 -0
- package/assets/icon.png +0 -0
- package/assets/onboarding/image1.png +0 -0
- package/assets/onboarding/image1D.png +0 -0
- package/assets/onboarding/image2.png +0 -0
- package/assets/onboarding/image2D.png +0 -0
- package/assets/onboarding/image3.png +0 -0
- package/assets/onboarding/image3D.png +0 -0
- package/assets/onboarding/slides.js +22 -0
- package/assets/splash-icon.png +0 -0
- package/components/CDSBottomSheet.jsx +163 -0
- package/components/CDSButton.jsx +95 -0
- package/components/CDSCarousel.jsx +60 -0
- package/components/CDSCarouselDots.jsx +56 -0
- package/components/CDSInput.jsx +54 -0
- package/components/CDSOnboarding.jsx +70 -0
- package/components/CDSSwitch.jsx +29 -0
- package/components/CustomSlotDebug.jsx +14 -0
- package/components/Onboarding.jsx +65 -0
- package/components/Paginator.jsx +52 -0
- package/components/onboardingItem.jsx +39 -0
- package/context/CDSThemeContext.js +52 -0
- package/index.js +21 -0
- package/package.json +28 -0
- package/tokens/CDSprimitiveTokens.js +146 -0
- package/tokens/CDSsemanticColors.js +213 -0
- package/tokens/CDSsemanticTextStyles.js +208 -0
package/.expo/README.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
> Why do I have a folder named ".expo" in my project?
|
|
2
|
+
The ".expo" folder is created when an Expo project is started using "expo start" command.
|
|
3
|
+
> What do the files contain?
|
|
4
|
+
- "devices.json": contains information about devices that have recently opened this project. This is used to populate the "Development sessions" list in your development builds.
|
|
5
|
+
- "settings.json": contains the server configuration that is used to serve the application manifest.
|
|
6
|
+
> Should I commit the ".expo" folder?
|
|
7
|
+
No, you should not share the ".expo" folder. It does not contain any information that is relevant for other developers working on the project, it is specific to your machine.
|
|
8
|
+
Upon project creation, the ".expo" folder is already added to your ".gitignore" file.
|
|
Binary file
|
package/app.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"expo": {
|
|
3
|
+
"name": "CDSLibrary",
|
|
4
|
+
"slug": "CDSLibrary",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"orientation": "portrait",
|
|
7
|
+
"icon": "./assets/icon.png",
|
|
8
|
+
"userInterfaceStyle": "auto",
|
|
9
|
+
"newArchEnabled": true,
|
|
10
|
+
"ios": {
|
|
11
|
+
"supportsTablet": true
|
|
12
|
+
},
|
|
13
|
+
"android": {
|
|
14
|
+
"adaptiveIcon": {
|
|
15
|
+
"foregroundImage": "./assets/adaptive-icon.png",
|
|
16
|
+
"backgroundColor": "#ffffff"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"web": {
|
|
20
|
+
"favicon": "./assets/favicon.png"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
Binary file
|
|
Binary file
|
package/assets/icon.png
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// slides.js
|
|
2
|
+
export const getSlides = (isDarkMode) => [
|
|
3
|
+
{
|
|
4
|
+
id: 'slide1',
|
|
5
|
+
title: "Tus boletas en un solo lugar",
|
|
6
|
+
description: "Conoce el estado general de tus boletas y dales seguimiento desde la aplicación.",
|
|
7
|
+
image: isDarkMode ? require("./image1D.png") : require("./image1.png")
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
id: 'slide2',
|
|
11
|
+
title: "Realiza tus pagos",
|
|
12
|
+
description: "Puedes refrendar o pagar tus desempeños con diferentes métodos de pago.",
|
|
13
|
+
image: isDarkMode ? require("./image2D.png") : require("./image2.png")
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: 'slide3',
|
|
17
|
+
title: "Tu eliges cuánto pagar",
|
|
18
|
+
description: "Puedes elegir la cantidad que deseas pagar en tus boletas.",
|
|
19
|
+
// Revisa que el uso de imágenes sea correcto según el modo:
|
|
20
|
+
image: isDarkMode ? require("./image3D.png") : require("./image3.png")
|
|
21
|
+
}
|
|
22
|
+
];
|
|
Binary file
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { View, Text, Animated, Dimensions, StyleSheet, Pressable, Platform } from "react-native";
|
|
3
|
+
import { CDSButton } from "./CDSButton";
|
|
4
|
+
|
|
5
|
+
import { MaterialIcons } from "@expo/vector-icons";
|
|
6
|
+
import { useTheme } from "../context/CDSThemeContext";
|
|
7
|
+
import { getSemanticTextStyles } from "../tokens/CDSsemanticTextStyles";
|
|
8
|
+
|
|
9
|
+
const { height, width } = Dimensions.get("window");
|
|
10
|
+
|
|
11
|
+
const isMobile = width <= 878;
|
|
12
|
+
|
|
13
|
+
export const CDSBottomSheet = ({
|
|
14
|
+
type,
|
|
15
|
+
isVisible,
|
|
16
|
+
hasClose,
|
|
17
|
+
title,
|
|
18
|
+
description ,
|
|
19
|
+
customSlot,
|
|
20
|
+
primaryButtonLabel,
|
|
21
|
+
primaryButtonOnPress,
|
|
22
|
+
secondaryButtonLabel = "Cancelar",
|
|
23
|
+
onFinish,
|
|
24
|
+
}) => {
|
|
25
|
+
|
|
26
|
+
const [childHeight, setChildHeight] = useState(0);
|
|
27
|
+
const handleLayout = (event) => {
|
|
28
|
+
const { width } = event.nativeEvent.layout;
|
|
29
|
+
console.log("Ancho:", width, "Alto:", height);
|
|
30
|
+
setChildHeight(width); // Guardamos el ancho en el estado
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const { theme } = useTheme();
|
|
34
|
+
const textStyles = getSemanticTextStyles(theme);
|
|
35
|
+
|
|
36
|
+
const [modalVisible, setModalVisible] = useState(isVisible);
|
|
37
|
+
const [modalOpacity] = useState(new Animated.Value(0));
|
|
38
|
+
const [slidePosition] = useState(new Animated.Value(height));
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
Animated.parallel([
|
|
42
|
+
Animated.timing(modalOpacity, {
|
|
43
|
+
toValue: modalVisible ? 1 : 0,
|
|
44
|
+
duration: 500,
|
|
45
|
+
useNativeDriver: false,
|
|
46
|
+
}),
|
|
47
|
+
Animated.timing(slidePosition, {
|
|
48
|
+
toValue: modalVisible ? 0 : height,
|
|
49
|
+
duration: modalVisible ? 500 : 800,
|
|
50
|
+
useNativeDriver: false,
|
|
51
|
+
}),
|
|
52
|
+
]).start();
|
|
53
|
+
}, [modalVisible]);
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<>
|
|
57
|
+
<Animated.View onLayout={handleLayout}
|
|
58
|
+
style={[isMobile ? styles.centeredView.typeBottomSheet : styles.centeredView.typeModal,
|
|
59
|
+
{opacity: modalOpacity, transform: isMobile && [{ translateY: slidePosition }] },
|
|
60
|
+
]}
|
|
61
|
+
>
|
|
62
|
+
<View style={[isMobile ? styles.container.typeBottomSheet : styles.container.typeModal, { backgroundColor: theme.surface.neutral.primary } ]}>
|
|
63
|
+
{hasClose && (
|
|
64
|
+
<MaterialIcons
|
|
65
|
+
name={"close"}
|
|
66
|
+
size={textStyles.icon.fontSize}
|
|
67
|
+
color={"red"}
|
|
68
|
+
style={{ position: "absolute", right: 16, top: 16 }}
|
|
69
|
+
/>
|
|
70
|
+
)}
|
|
71
|
+
{title && <Text style={textStyles.bold.lg}>{title}</Text>}
|
|
72
|
+
{description && (
|
|
73
|
+
<Text style={textStyles.regular.md}>{description}</Text>
|
|
74
|
+
)}
|
|
75
|
+
{customSlot && <View style={{ height: childHeight,}}>{customSlot}</View>}
|
|
76
|
+
{type !== "informative" && (
|
|
77
|
+
<View style={styles.actionsContainer}>
|
|
78
|
+
<CDSButton
|
|
79
|
+
label={primaryButtonLabel}
|
|
80
|
+
onPress={
|
|
81
|
+
onFinish
|
|
82
|
+
? () => settypeMVisible(!modalVisible)
|
|
83
|
+
: primaryButtonOnPress
|
|
84
|
+
}
|
|
85
|
+
/>
|
|
86
|
+
<CDSButton
|
|
87
|
+
label={secondaryButtonLabel}
|
|
88
|
+
type="ghost"
|
|
89
|
+
onPress={() => setModalVisible(!modalVisible)}
|
|
90
|
+
/>
|
|
91
|
+
</View>
|
|
92
|
+
)}
|
|
93
|
+
</View>
|
|
94
|
+
</Animated.View>
|
|
95
|
+
<Animated.View
|
|
96
|
+
style={[
|
|
97
|
+
styles.overlay,
|
|
98
|
+
{
|
|
99
|
+
opacity: modalOpacity,
|
|
100
|
+
backgroundColor: theme.surface.special.overlay,
|
|
101
|
+
},
|
|
102
|
+
]}
|
|
103
|
+
>
|
|
104
|
+
<Pressable onPress={() => setModalVisible(false)} style={{ flex: 1 }} />
|
|
105
|
+
</Animated.View>
|
|
106
|
+
</>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const styles = StyleSheet.create({
|
|
111
|
+
overlay: {
|
|
112
|
+
position: "absolute",
|
|
113
|
+
top: 0,
|
|
114
|
+
left: 0,
|
|
115
|
+
width: "110%",
|
|
116
|
+
height: "104.4%",
|
|
117
|
+
zIndex: 9,
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
centeredView: {
|
|
121
|
+
typeBottomSheet: {
|
|
122
|
+
flex: 1,
|
|
123
|
+
justifyContent: "flex-end",
|
|
124
|
+
alignItems: "center",
|
|
125
|
+
zIndex: 99,
|
|
126
|
+
pointerEvents: "none",
|
|
127
|
+
width: "100%",
|
|
128
|
+
},
|
|
129
|
+
typeModal: {
|
|
130
|
+
justifyContent: "center",
|
|
131
|
+
alignItems: "center",
|
|
132
|
+
zIndex: 99,
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
container: {
|
|
136
|
+
typeBottomSheet: {
|
|
137
|
+
width: "100%",
|
|
138
|
+
borderTopLeftRadius: 16,
|
|
139
|
+
borderTopRightRadius: 16,
|
|
140
|
+
paddingHorizontal: 16,
|
|
141
|
+
paddingVertical: 24,
|
|
142
|
+
gap: 16,
|
|
143
|
+
zIndex: 100,
|
|
144
|
+
pointerEvents: "all",
|
|
145
|
+
},
|
|
146
|
+
typeModal: {
|
|
147
|
+
width: 600,
|
|
148
|
+
borderRadius: 16,
|
|
149
|
+
paddingHorizontal: 16,
|
|
150
|
+
paddingVertical: 24,
|
|
151
|
+
gap: 16,
|
|
152
|
+
zIndex: 100,
|
|
153
|
+
pointerEvents: "all",
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
actionsContainer: {
|
|
157
|
+
flex: "row",
|
|
158
|
+
width: "100%",
|
|
159
|
+
gap: 8,
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
});
|
|
163
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Text, StyleSheet, TouchableOpacity } from "react-native";
|
|
3
|
+
import { Dimensions, Platform } from "react-native";
|
|
4
|
+
import { MaterialIcons } from "@expo/vector-icons";
|
|
5
|
+
import { useTheme } from "../context/CDSThemeContext";
|
|
6
|
+
import {getSemanticTextStyles} from "../tokens/CDSsemanticTextStyles";
|
|
7
|
+
|
|
8
|
+
const { width } = Dimensions.get("window");
|
|
9
|
+
const isMobile = width <= 878 && Platform.OS !== "web";
|
|
10
|
+
|
|
11
|
+
export const CDSButton = ({
|
|
12
|
+
label,
|
|
13
|
+
type = "primary",
|
|
14
|
+
size,
|
|
15
|
+
onPress,
|
|
16
|
+
icon,
|
|
17
|
+
flexend,
|
|
18
|
+
}) => {
|
|
19
|
+
const { theme } = useTheme();
|
|
20
|
+
const textStyles = getSemanticTextStyles(theme);
|
|
21
|
+
|
|
22
|
+
const backgroundColor =
|
|
23
|
+
type === "disabled"
|
|
24
|
+
? theme.surface.action.disabled
|
|
25
|
+
: type === "secondary" || type === "ghost" || type === "link"
|
|
26
|
+
? "transparent"
|
|
27
|
+
: theme.surface.action.primary;
|
|
28
|
+
|
|
29
|
+
const textColor =
|
|
30
|
+
type === "secondary" || type === "ghost" || type === "link"
|
|
31
|
+
? theme.text.neutral.primary
|
|
32
|
+
: type === "disabled"
|
|
33
|
+
? theme.text.neutral.disabled
|
|
34
|
+
: theme.text.neutral.contrast;
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<TouchableOpacity
|
|
38
|
+
onPress={type !== "disabled" ? onPress : null}
|
|
39
|
+
activeOpacity={0.7}
|
|
40
|
+
style={[
|
|
41
|
+
styles.container,
|
|
42
|
+
{ backgroundColor },
|
|
43
|
+
flexend && { justifyContent: "flex-end", paddingHorizontal: 0 },
|
|
44
|
+
isMobile && type !== "icon"
|
|
45
|
+
? { width: "100%" }
|
|
46
|
+
: { paddingHorizontal: 12 },
|
|
47
|
+
type === "secondary" && {
|
|
48
|
+
borderColor: theme.outline.action.primary,
|
|
49
|
+
borderWidth: 1,
|
|
50
|
+
},
|
|
51
|
+
type === 'link' && {
|
|
52
|
+
paddingHorizontal: 0,
|
|
53
|
+
paddingVertical: 0,
|
|
54
|
+
width: 'auto',
|
|
55
|
+
}
|
|
56
|
+
]}
|
|
57
|
+
>
|
|
58
|
+
{type !== "icon" && (
|
|
59
|
+
<Text
|
|
60
|
+
style={[
|
|
61
|
+
type === "link"
|
|
62
|
+
? size === "small"
|
|
63
|
+
? textStyles.link.small
|
|
64
|
+
: textStyles.link.regular
|
|
65
|
+
: textStyles.buttonText,
|
|
66
|
+
{ color: textColor },
|
|
67
|
+
]}
|
|
68
|
+
>
|
|
69
|
+
{label}
|
|
70
|
+
</Text>
|
|
71
|
+
)}
|
|
72
|
+
{icon && (
|
|
73
|
+
<MaterialIcons
|
|
74
|
+
name={icon}
|
|
75
|
+
size={textStyles.icon.fontSize}
|
|
76
|
+
color={textColor}
|
|
77
|
+
/>
|
|
78
|
+
)}
|
|
79
|
+
</TouchableOpacity>
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const styles = StyleSheet.create({
|
|
84
|
+
container: {
|
|
85
|
+
minWidth: 343,
|
|
86
|
+
flexDirection: "row",
|
|
87
|
+
alignItems: "center",
|
|
88
|
+
justifyContent: "center",
|
|
89
|
+
paddingVertical: 12,
|
|
90
|
+
paddingHorizontal: 24,
|
|
91
|
+
borderRadius: 100,
|
|
92
|
+
gap: 8,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { View, Image, ScrollView, Dimensions } from "react-native";
|
|
3
|
+
import { useTheme } from "../context/CDSThemeContext";
|
|
4
|
+
// const { width } = Dimensions.get("window");
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export const CDSCarousel = ({ activeIndex, scrollViewRef, onScroll, images }) => {
|
|
9
|
+
const { theme } = useTheme();
|
|
10
|
+
const [scrollViewWidth, setScrollViewWidth] = useState(0);
|
|
11
|
+
|
|
12
|
+
const onLayout = (event) => {
|
|
13
|
+
const { width } = event.nativeEvent.layout;
|
|
14
|
+
setScrollViewWidth(width); // Establece el ancho del ScrollView
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<View style={{ alignItems: "center", marginTop: 20 }}>
|
|
19
|
+
<ScrollView
|
|
20
|
+
ref={scrollViewRef}
|
|
21
|
+
horizontal
|
|
22
|
+
pagingEnabled
|
|
23
|
+
showsHorizontalScrollIndicator={false}
|
|
24
|
+
onScroll={onScroll}
|
|
25
|
+
scrollEventThrottle={16}
|
|
26
|
+
style={{ width: '100%', }}
|
|
27
|
+
contentContainerStyle={{ width: scrollViewWidth * images.length, alignItems: 'center' }
|
|
28
|
+
}
|
|
29
|
+
onLayout={onLayout}
|
|
30
|
+
>
|
|
31
|
+
{images.map((image, index) => (
|
|
32
|
+
<View key={index} style={{ width: scrollViewWidth, justifyContent: 'center', alignItems: 'center', backgroundColor: 'red' }}>
|
|
33
|
+
<Image
|
|
34
|
+
source={image}
|
|
35
|
+
style={{
|
|
36
|
+
height: 353,
|
|
37
|
+
}}
|
|
38
|
+
resizeMode={"cover"}
|
|
39
|
+
/>
|
|
40
|
+
</View>
|
|
41
|
+
))}
|
|
42
|
+
</ScrollView>
|
|
43
|
+
<View style={{ flexDirection: "row", marginTop: 10 }}>
|
|
44
|
+
{images.map((_, index) => (
|
|
45
|
+
<View
|
|
46
|
+
key={index}
|
|
47
|
+
style={{
|
|
48
|
+
width: activeIndex === index ? 14 : 10,
|
|
49
|
+
height: 10,
|
|
50
|
+
borderRadius: 5,
|
|
51
|
+
backgroundColor: activeIndex === index ? theme.surface.special.progress : theme.surface.special.progressbarBg,
|
|
52
|
+
marginHorizontal: 5,
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
))}
|
|
56
|
+
</View>
|
|
57
|
+
</View>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View, Animated, StyleSheet, Dimensions } from "react-native";
|
|
3
|
+
|
|
4
|
+
const { width } = Dimensions.get("window");
|
|
5
|
+
|
|
6
|
+
const PaginationDots = ({ data, scrollX, itemWidth }) => {
|
|
7
|
+
const dotWidth = 10; // Ancho de cada dot
|
|
8
|
+
const spacing = 5; // Espaciado entre dots
|
|
9
|
+
|
|
10
|
+
// Calcular la posición del dot activo
|
|
11
|
+
const translateX = scrollX.interpolate({
|
|
12
|
+
inputRange: data.map((_, index) => index * itemWidth),
|
|
13
|
+
outputRange: data.map((_, index) => index * (dotWidth + spacing)),
|
|
14
|
+
extrapolate: "clamp",
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<View style={styles.container}>
|
|
19
|
+
{/* Dots estáticos */}
|
|
20
|
+
{data.map((_, index) => (
|
|
21
|
+
<View key={index} style={styles.dot} />
|
|
22
|
+
))}
|
|
23
|
+
|
|
24
|
+
{/* Dot animado que se mueve */}
|
|
25
|
+
<Animated.View
|
|
26
|
+
style={[styles.activeDot, { transform: [{ translateX }] }]}
|
|
27
|
+
/>
|
|
28
|
+
</View>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const styles = StyleSheet.create({
|
|
33
|
+
container: {
|
|
34
|
+
flexDirection: "row",
|
|
35
|
+
marginTop: 10,
|
|
36
|
+
justifyContent: "center",
|
|
37
|
+
position: "relative",
|
|
38
|
+
},
|
|
39
|
+
dot: {
|
|
40
|
+
width: 10,
|
|
41
|
+
height: 10,
|
|
42
|
+
borderRadius: 5,
|
|
43
|
+
backgroundColor: "gray",
|
|
44
|
+
marginHorizontal: 5,
|
|
45
|
+
},
|
|
46
|
+
activeDot: {
|
|
47
|
+
width: 10,
|
|
48
|
+
height: 10,
|
|
49
|
+
borderRadius: 5,
|
|
50
|
+
backgroundColor: "black",
|
|
51
|
+
position: "absolute",
|
|
52
|
+
left: 0,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export default PaginationDots;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { StyleSheet, Text, TextInput, View } from "react-native";
|
|
2
|
+
import { useTheme } from "../context/CDSThemeContext";
|
|
3
|
+
import getSemanticTextStyles from "../tokens/CDSsemanticTextStyles";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
|
|
6
|
+
export default function StyledInput({ label, type, keyboard, placeholder }) {
|
|
7
|
+
const { theme } = useTheme();
|
|
8
|
+
const textStyles = getSemanticTextStyles(theme);
|
|
9
|
+
const [text, setText] = useState("");
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<View style={[styles.container]}>
|
|
13
|
+
<Text
|
|
14
|
+
style={[
|
|
15
|
+
textStyles.label,
|
|
16
|
+
]}
|
|
17
|
+
>
|
|
18
|
+
{label}
|
|
19
|
+
</Text>
|
|
20
|
+
{text === "" && (
|
|
21
|
+
<Text style={[styles.fakePlaceholder, textStyles.inputText.placeholder]}>
|
|
22
|
+
{placeholder}
|
|
23
|
+
</Text>
|
|
24
|
+
)}
|
|
25
|
+
<TextInput
|
|
26
|
+
style={[styles.textBox, textStyles.inputText.value, {backgroundColor:theme.surface.neutral.primary, borderColor: theme.outline.neutral.primary }]}
|
|
27
|
+
keyboardType={keyboard}
|
|
28
|
+
secureTextEntry={type === "password" ? true : false}
|
|
29
|
+
onChangeText={setText}
|
|
30
|
+
value={text}
|
|
31
|
+
/>
|
|
32
|
+
</View>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const styles = StyleSheet.create({
|
|
37
|
+
container: {
|
|
38
|
+
width: "100%",
|
|
39
|
+
gap: 8,
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
fakePlaceholder: {
|
|
43
|
+
position: "absolute",
|
|
44
|
+
zIndex: 1,
|
|
45
|
+
left: 14,
|
|
46
|
+
top: 40,
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
textBox: {
|
|
50
|
+
padding: 12,
|
|
51
|
+
borderRadius: 8,
|
|
52
|
+
borderWidth: 1,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React, { act, useRef, useState } from "react";
|
|
2
|
+
import { Dimensions } from "react-native";
|
|
3
|
+
import {CDSBottomSheet} from "./CDSBottomSheet";
|
|
4
|
+
import {CDSCarousel} from "./CDSCarousel";
|
|
5
|
+
import { useTheme } from "../context/CDSThemeContext";
|
|
6
|
+
import { Onboarding } from "./Onboarding";
|
|
7
|
+
const { width } = Dimensions.get("window");
|
|
8
|
+
|
|
9
|
+
export const CDSOnboarding = () => {
|
|
10
|
+
const { isDarkMode } = useTheme();
|
|
11
|
+
const scrollViewRef = useRef(null);
|
|
12
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
13
|
+
const [isLastSlide, setIsLastSlide] = useState(false);
|
|
14
|
+
|
|
15
|
+
const images = !isDarkMode
|
|
16
|
+
? [
|
|
17
|
+
require("../assets/onboarding/image1.png"),
|
|
18
|
+
require("../assets/onboarding/image2.png"),
|
|
19
|
+
require("../assets/onboarding/image3.png"),
|
|
20
|
+
]
|
|
21
|
+
: [
|
|
22
|
+
require("../assets/onboarding/image1D.png"),
|
|
23
|
+
require("../assets/onboarding/image2D.png"),
|
|
24
|
+
require("../assets/onboarding/image3D.png"),
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const handleScroll = (event) => {
|
|
28
|
+
const index = Math.round(event.nativeEvent.contentOffset.x / width);
|
|
29
|
+
setActiveIndex(index);
|
|
30
|
+
setIsLastSlide(index === images.length - 1);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const handleNext = () =>
|
|
34
|
+
!isLastSlide &&
|
|
35
|
+
scrollViewRef.current.scrollTo({
|
|
36
|
+
x: (activeIndex + 1) * width,
|
|
37
|
+
animated: true,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<CDSBottomSheet
|
|
42
|
+
isVisible
|
|
43
|
+
customSlot={
|
|
44
|
+
<CDSCarousel
|
|
45
|
+
activeIndex={activeIndex}
|
|
46
|
+
scrollViewRef={scrollViewRef}
|
|
47
|
+
onScroll={handleScroll}
|
|
48
|
+
images={images}
|
|
49
|
+
/>
|
|
50
|
+
}
|
|
51
|
+
title={
|
|
52
|
+
(activeIndex === 0 && "Tus boletas en un solo lugar") ||
|
|
53
|
+
(activeIndex === 1 && "Realiza tus pagos") ||
|
|
54
|
+
(activeIndex === 2 && "Tu eliges cuánto pagar")
|
|
55
|
+
}
|
|
56
|
+
description={
|
|
57
|
+
(activeIndex === 0 &&
|
|
58
|
+
"Conoce el estado general de tus boletas y dales seguimiento desde la aplicación.") ||
|
|
59
|
+
(activeIndex === 1 &&
|
|
60
|
+
"Puedes refrendar o pagar tus desempeños con diferentes métodos de pago.") ||
|
|
61
|
+
(activeIndex === 2 &&
|
|
62
|
+
"Con “Pagos libres” elige la cantidad, reduce los intereses y abona a capital desde el primer día.")
|
|
63
|
+
}
|
|
64
|
+
primaryButtonLabel={!isLastSlide ? "Siguiente" : "Finalizar"}
|
|
65
|
+
primaryButtonOnPress={handleNext}
|
|
66
|
+
onFinish={isLastSlide && true}
|
|
67
|
+
secondaryButtonLabel="Ahora no"
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { View, Text, Switch, StyleSheet } from "react-native";
|
|
3
|
+
import { useTheme } from "../context/CDSThemeContext";
|
|
4
|
+
import getSemanticTextStyles from "../tokens/CDSsemanticTextStyles";
|
|
5
|
+
|
|
6
|
+
export default function CDSSwitch({ label }) {
|
|
7
|
+
const { theme } = useTheme();
|
|
8
|
+
const textStyles = getSemanticTextStyles(theme);
|
|
9
|
+
const [isEnabled, setIsEnabled] = useState(false);
|
|
10
|
+
|
|
11
|
+
const toggleSwitch = () => setIsEnabled((previousState) => !previousState);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<View style={styles.container}>
|
|
15
|
+
<Text style={textStyles.label}>
|
|
16
|
+
{label}
|
|
17
|
+
</Text>
|
|
18
|
+
<Switch onValueChange={toggleSwitch} value={isEnabled} />
|
|
19
|
+
</View>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const styles = StyleSheet.create({
|
|
24
|
+
container: {
|
|
25
|
+
flexDirection: "row",
|
|
26
|
+
justifyContent: "space-between",
|
|
27
|
+
alignItems: "center",
|
|
28
|
+
},
|
|
29
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { Platform } from 'react-native';
|
|
3
|
+
|
|
4
|
+
const CustomSlotDebug = ({ customSlot, isVisible }) => {
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
console.log('Platform:', Platform.OS);
|
|
7
|
+
console.log('Custom Slot:', customSlot);
|
|
8
|
+
console.log('Is Visible:', isVisible);
|
|
9
|
+
}, [customSlot, isVisible]);
|
|
10
|
+
|
|
11
|
+
return <>{customSlot}</>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default CustomSlotDebug;
|