Interactive component setup
This commit is contained in:
+131
-113
@@ -1,6 +1,9 @@
|
|||||||
import React, { useRef, useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Animated, StyleSheet, TouchableOpacity, Text, ActivityIndicator, View, Image } from 'react-native';
|
import { StyleSheet, ActivityIndicator, View, Image } from 'react-native';
|
||||||
import Ionicons from '@expo/vector-icons/Ionicons';
|
import Ionicons from '@expo/vector-icons/Ionicons';
|
||||||
|
import InteractiveBase from './InteractiveBase';
|
||||||
|
import { Text, useTheme } from 'native-base';
|
||||||
|
// import { BlurView } from 'expo-blur';
|
||||||
|
|
||||||
interface ButtonProps {
|
interface ButtonProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
@@ -9,139 +12,154 @@ interface ButtonProps {
|
|||||||
icon?: string;
|
icon?: string;
|
||||||
iconImage?: string;
|
iconImage?: string;
|
||||||
isCollapsed?: boolean;
|
isCollapsed?: boolean;
|
||||||
isOutlined?: boolean;
|
type: 'filled' | 'outlined' | 'menu' | 'submenu';
|
||||||
}
|
}
|
||||||
|
|
||||||
const ButtonBase: React.FC<ButtonProps> = ({ title, onPress, isDisabled, icon, iconImage, isCollapsed, isOutlined = false }) => {
|
const ButtonBase: React.FC<ButtonProps> = ({ title, onPress, isDisabled, icon, iconImage, isCollapsed, type = 'filled'}) => {
|
||||||
const shouldCollapse = isCollapsed !== undefined ? isCollapsed : (!title && (icon || iconImage));
|
const { colors } = useTheme();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const scaleValue = useRef(new Animated.Value(1)).current;
|
|
||||||
const colorValue = useRef(new Animated.Value(0)).current;
|
|
||||||
const backgroundColor = colorValue.interpolate({
|
|
||||||
inputRange: [0, 1],
|
|
||||||
outputRange: isOutlined ? ['transparent', 'transparent'] : ['#6075F9', '#4352ae'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const borderColor = colorValue.interpolate({
|
const styleButton = StyleSheet.create({
|
||||||
inputRange: [0, 1],
|
Default: {
|
||||||
outputRange: ['#6075F9', '#4352ae'],
|
scale: 1,
|
||||||
});
|
shadowOpacity: 0.30,
|
||||||
|
shadowRadius: 4.65,
|
||||||
const textColor = colorValue.interpolate({
|
elevation: 8,
|
||||||
inputRange: [0, 1],
|
backgroundColor: colors.primary[400],
|
||||||
outputRange: isOutlined ? ['#6075F9', '#4352ae'] : ['#ffffff', '#ffffff'],
|
},
|
||||||
});
|
onHover: {
|
||||||
|
scale: 1.02,
|
||||||
// scale animation onClick
|
shadowOpacity: 0.37,
|
||||||
const handlePressIn = () => {
|
shadowRadius: 7.49,
|
||||||
Animated.spring(scaleValue, {
|
elevation: 12,
|
||||||
toValue: 0.98,
|
backgroundColor: colors.primary[500],
|
||||||
useNativeDriver: true,
|
},
|
||||||
}).start();
|
onPressed: {
|
||||||
};
|
scale: 0.98,
|
||||||
|
shadowOpacity: 0.23,
|
||||||
// scale animation reset after onClick
|
shadowRadius: 2.62,
|
||||||
const handlePressOut = async () => {
|
elevation: 4,
|
||||||
Animated.spring(scaleValue, {
|
backgroundColor: colors.primary[600],
|
||||||
toValue: 1,
|
},
|
||||||
friction: 30,
|
Disabled: {
|
||||||
// tension: 50,
|
scale: 1,
|
||||||
useNativeDriver: true,
|
shadowOpacity: 0.30,
|
||||||
}).start();
|
shadowRadius: 4.65,
|
||||||
|
elevation: 8,
|
||||||
if (onPress && !isDisabled) {
|
backgroundColor: colors.primary[400],
|
||||||
setLoading(true);
|
|
||||||
await onPress();
|
|
||||||
setLoading(false);
|
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// color animation onHover
|
const styleMenu = StyleSheet.create({
|
||||||
const handleMouseEnter = () => {
|
Default: {
|
||||||
Animated.timing(colorValue, {
|
scale: 1,
|
||||||
toValue: 1,
|
shadowOpacity: 0.30,
|
||||||
duration: 250,
|
shadowRadius: 4.65,
|
||||||
useNativeDriver: false,
|
elevation: 8,
|
||||||
}).start();
|
backgroundColor: '#ff0000',
|
||||||
};
|
},
|
||||||
|
onHover: {
|
||||||
|
scale: 1.01,
|
||||||
|
shadowOpacity: 0.37,
|
||||||
|
shadowRadius: 7.49,
|
||||||
|
elevation: 12,
|
||||||
|
backgroundColor: '#0ff000',
|
||||||
|
},
|
||||||
|
onPressed: {
|
||||||
|
scale: 0.99,
|
||||||
|
shadowOpacity: 0.23,
|
||||||
|
shadowRadius: 2.62,
|
||||||
|
elevation: 4,
|
||||||
|
backgroundColor: '#000',
|
||||||
|
},
|
||||||
|
Disabled: {
|
||||||
|
scale: 1,
|
||||||
|
shadowOpacity: 0.30,
|
||||||
|
shadowRadius: 4.65,
|
||||||
|
elevation: 8,
|
||||||
|
backgroundColor: '#0000',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// color animation reset after onHover
|
const typeToStyleAnimator = {'filled': styleButton,'outlined': styleButton,'menu': styleMenu,'submenu': styleButton};
|
||||||
const handleMouseLeave = () => {
|
|
||||||
Animated.timing(colorValue, {
|
|
||||||
toValue: 0,
|
|
||||||
duration: 250,
|
|
||||||
useNativeDriver: false,
|
|
||||||
}).start();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={shouldCollapse ? styles.collapsedContainer : styles.container}>
|
<InteractiveBase
|
||||||
<TouchableOpacity
|
style={styles.container}
|
||||||
activeOpacity={1}
|
styleAnimate={typeToStyleAnimator[type]}
|
||||||
onPressIn={handlePressIn}
|
onPress={async () => {
|
||||||
onPressOut={handlePressOut}
|
if (onPress && !isDisabled) {
|
||||||
disabled={isDisabled || loading}
|
setLoading(true);
|
||||||
style={styles.buttonContainer}
|
await onPress();
|
||||||
onMouseEnter={handleMouseEnter}
|
setLoading(false);
|
||||||
onMouseLeave={handleMouseLeave}
|
}
|
||||||
>
|
}}
|
||||||
<Animated.View
|
isDisabled={isDisabled}
|
||||||
style={[
|
isOutlined={type === 'outlined'}
|
||||||
styles.button,
|
>
|
||||||
{
|
{loading ? (
|
||||||
backgroundColor: isDisabled ? '#454562' : backgroundColor,
|
<ActivityIndicator size="small" color={type === 'outlined' ? '#6075F9' : '#FFFFFF'} />
|
||||||
transform: [{ scale: scaleValue }],
|
) : (
|
||||||
borderWidth: isOutlined ? 2 : 0,
|
<View style={styles.content}>
|
||||||
borderColor,
|
{icon && <Ionicons name={icon} size={18} color={type === 'outlined' ? '#ff0000' : '#FFFFFF'} />}
|
||||||
padding: (icon || iconImage) ? 12 : 16
|
{iconImage && <Image source={{uri: iconImage}} style={styles.icon} />}
|
||||||
},
|
{title && <Text style={styles.text}>{title}</Text>}
|
||||||
]}
|
</View>
|
||||||
>
|
)}
|
||||||
{loading ? (
|
</InteractiveBase>
|
||||||
<ActivityIndicator size="small" color={isOutlined ? '#6075F9' : '#FFFFFF'} />
|
|
||||||
) : (
|
|
||||||
<View style={styles.content}>
|
|
||||||
{icon && <Ionicons name={icon} size={24} color={isOutlined ? '#6075F9' : '#FFFFFF'} />}
|
|
||||||
{iconImage && <Image source={{uri: iconImage}} style={styles.icon} />}
|
|
||||||
{title && <Animated.Text style={[styles.text, { color: textColor }]}>{title}</Animated.Text>}
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</Animated.View>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const styleAnimate = StyleSheet.create({
|
||||||
|
Default: {
|
||||||
|
scale: 1,
|
||||||
|
shadowOpacity: 0.30,
|
||||||
|
shadowRadius: 4.65,
|
||||||
|
elevation: 8,
|
||||||
|
backgroundColor: '#00ff00',
|
||||||
|
},
|
||||||
|
onHover: {
|
||||||
|
scale: 1.01,
|
||||||
|
shadowOpacity: 0.37,
|
||||||
|
shadowRadius: 7.49,
|
||||||
|
elevation: 12,
|
||||||
|
backgroundColor: '#0000ff',
|
||||||
|
},
|
||||||
|
onPressed: {
|
||||||
|
scale: 0.99,
|
||||||
|
shadowOpacity: 0.23,
|
||||||
|
shadowRadius: 2.62,
|
||||||
|
elevation: 4,
|
||||||
|
backgroundColor: '#ff0000',
|
||||||
|
},
|
||||||
|
Disabled: {
|
||||||
|
scale: 1,
|
||||||
|
shadowOpacity: 0.30,
|
||||||
|
shadowRadius: 4.65,
|
||||||
|
elevation: 8,
|
||||||
|
backgroundColor: '#000000',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
width: '100%',
|
borderRadius: 8,
|
||||||
},
|
},
|
||||||
collapsedContainer: {
|
content: {
|
||||||
width: 'fit-content',
|
padding: 10,
|
||||||
// alignItems: 'center',
|
|
||||||
},
|
|
||||||
buttonContainer: {
|
|
||||||
borderRadius: 16,
|
|
||||||
},
|
|
||||||
button: {
|
|
||||||
borderRadius: 16,
|
|
||||||
padding: 16,
|
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
|
icon: {
|
||||||
|
width: 18,
|
||||||
|
height: 18,
|
||||||
|
// marginRight: 8,
|
||||||
|
},
|
||||||
text: {
|
text: {
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
marginHorizontal: 8
|
marginHorizontal: 8
|
||||||
},
|
},
|
||||||
content: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
icon: {
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
// marginRight: 8,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default ButtonBase;
|
export default ButtonBase;
|
||||||
|
|||||||
@@ -0,0 +1,245 @@
|
|||||||
|
import React, { useRef, useState } from 'react';
|
||||||
|
import { Animated, StyleSheet, TouchableOpacity, ActivityIndicator, View, Image, StyleProp, ViewStyle } from 'react-native';
|
||||||
|
import Ionicons from '@expo/vector-icons/Ionicons';
|
||||||
|
import { Text, useTheme } from 'native-base'
|
||||||
|
import { BlurView } from 'expo-blur';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Fill,
|
||||||
|
BackdropBlur,
|
||||||
|
} from "@shopify/react-native-skia";
|
||||||
|
|
||||||
|
interface InteractiveBaseProps {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
onPress?: () => Promise<any>;
|
||||||
|
isDisabled?: boolean;
|
||||||
|
isOutlined?: boolean;
|
||||||
|
style?: StyleProp<ViewStyle>,
|
||||||
|
styleAnimate: {
|
||||||
|
Default: {
|
||||||
|
scale: number,
|
||||||
|
shadowOpacity: number,
|
||||||
|
shadowRadius: number,
|
||||||
|
elevation: number,
|
||||||
|
backgroundColor: string,
|
||||||
|
},
|
||||||
|
onHover: {
|
||||||
|
scale: number,
|
||||||
|
shadowOpacity: number,
|
||||||
|
shadowRadius: number,
|
||||||
|
elevation: number,
|
||||||
|
backgroundColor: string,
|
||||||
|
},
|
||||||
|
onPressed: {
|
||||||
|
scale: number,
|
||||||
|
shadowOpacity: number,
|
||||||
|
shadowRadius: number,
|
||||||
|
elevation: number,
|
||||||
|
backgroundColor: string,
|
||||||
|
},
|
||||||
|
Disabled: {
|
||||||
|
scale: number,
|
||||||
|
shadowOpacity: number,
|
||||||
|
shadowRadius: number,
|
||||||
|
elevation: number,
|
||||||
|
backgroundColor: string,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const InteractiveBase: React.FC<InteractiveBaseProps> = ({ children, onPress, style, styleAnimate, isDisabled = false, isOutlined = false }) => {
|
||||||
|
const scaleAnimator = useRef(new Animated.Value(1)).current;
|
||||||
|
const scaleValue = scaleAnimator.interpolate({
|
||||||
|
inputRange: [0, 1, 2],
|
||||||
|
outputRange: [styleAnimate.Default.scale, styleAnimate.onHover.scale, styleAnimate.onPressed.scale],
|
||||||
|
});
|
||||||
|
const shadowOpacityAnimator = useRef(new Animated.Value(0)).current;
|
||||||
|
const shadowOpacityValue = shadowOpacityAnimator.interpolate({
|
||||||
|
inputRange: [0, 1, 2],
|
||||||
|
outputRange: [styleAnimate.Default.shadowOpacity, styleAnimate.onHover.shadowOpacity, styleAnimate.onPressed.shadowOpacity],
|
||||||
|
});
|
||||||
|
const shadowRadiusAnimator = useRef(new Animated.Value(0)).current;
|
||||||
|
const shadowRadiusValue = shadowRadiusAnimator.interpolate({
|
||||||
|
inputRange: [0, 1, 2],
|
||||||
|
outputRange: [styleAnimate.Default.shadowRadius, styleAnimate.onHover.shadowRadius, styleAnimate.onPressed.shadowRadius],
|
||||||
|
});
|
||||||
|
const elevationAnimator = useRef(new Animated.Value(0)).current;
|
||||||
|
const elevationValue = elevationAnimator.interpolate({
|
||||||
|
inputRange: [0, 1, 2],
|
||||||
|
outputRange: [styleAnimate.Default.elevation, styleAnimate.onHover.elevation, styleAnimate.onPressed.elevation],
|
||||||
|
});
|
||||||
|
const backgroundColorAnimator = useRef(new Animated.Value(0)).current;
|
||||||
|
const backgroundColorValue = backgroundColorAnimator.interpolate({
|
||||||
|
inputRange: [0, 1, 2],
|
||||||
|
outputRange: [styleAnimate.Default.backgroundColor, styleAnimate.onHover.backgroundColor, styleAnimate.onPressed.backgroundColor],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mouse Enter
|
||||||
|
const handleMouseEnter = () => {
|
||||||
|
Animated.parallel([
|
||||||
|
Animated.spring(scaleAnimator, {
|
||||||
|
toValue: 1,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}),
|
||||||
|
Animated.timing(backgroundColorAnimator, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
Animated.timing(shadowRadiusAnimator, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
Animated.timing(shadowOpacityAnimator, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
Animated.timing(elevationAnimator, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
]).start();
|
||||||
|
}
|
||||||
|
// Mouse Down
|
||||||
|
const handlePressIn = () => {
|
||||||
|
Animated.parallel([
|
||||||
|
Animated.spring(scaleAnimator, {
|
||||||
|
toValue: 2,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}),
|
||||||
|
Animated.timing(backgroundColorAnimator, {
|
||||||
|
toValue: 2,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
Animated.timing(shadowRadiusAnimator, {
|
||||||
|
toValue: 2,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
Animated.timing(shadowOpacityAnimator, {
|
||||||
|
toValue: 2,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
Animated.timing(elevationAnimator, {
|
||||||
|
toValue: 2,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
]).start();
|
||||||
|
};
|
||||||
|
// Mouse Up
|
||||||
|
const handlePressOut = async () => {
|
||||||
|
Animated.parallel([
|
||||||
|
Animated.spring(scaleAnimator, {
|
||||||
|
toValue: 1,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}),
|
||||||
|
Animated.timing(backgroundColorAnimator, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
Animated.timing(shadowRadiusAnimator, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
Animated.timing(shadowOpacityAnimator, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
Animated.timing(elevationAnimator, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
]).start();
|
||||||
|
|
||||||
|
if (onPress && !isDisabled) {
|
||||||
|
await onPress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Mouse Leave
|
||||||
|
const handleMouseLeave = () => {
|
||||||
|
Animated.parallel([
|
||||||
|
Animated.spring(scaleAnimator, {
|
||||||
|
toValue: 0,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}),
|
||||||
|
Animated.timing(backgroundColorAnimator, {
|
||||||
|
toValue: 0,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
Animated.timing(shadowRadiusAnimator, {
|
||||||
|
toValue: 0,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
Animated.timing(shadowOpacityAnimator, {
|
||||||
|
toValue: 0,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}),
|
||||||
|
Animated.timing(elevationAnimator, {
|
||||||
|
toValue: 0,
|
||||||
|
duration: 250,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}),
|
||||||
|
]).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Animated.View
|
||||||
|
style={[
|
||||||
|
style,
|
||||||
|
isDisabled ? styleAnimate.Disabled : {
|
||||||
|
backgroundColor: isOutlined ? 'transparent' : backgroundColorValue,
|
||||||
|
borderColor: isOutlined ? backgroundColorValue : 'transparent',
|
||||||
|
borderWidth: 2,
|
||||||
|
transform: [{ scale: scaleValue }],
|
||||||
|
shadowOpacity: shadowOpacityValue,
|
||||||
|
shadowRadius: shadowRadiusValue,
|
||||||
|
elevation: elevationValue,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<TouchableOpacity
|
||||||
|
activeOpacity={1}
|
||||||
|
disabled={isDisabled}
|
||||||
|
onMouseEnter={handleMouseEnter}
|
||||||
|
onPressIn={handlePressIn}
|
||||||
|
onPressOut={handlePressOut}
|
||||||
|
onMouseLeave={handleMouseLeave}
|
||||||
|
style={styles.container}
|
||||||
|
>
|
||||||
|
{/* <BlurView
|
||||||
|
// style={[styles.container, {width: isCollapsed ? 'fit-content': '100%'}]}
|
||||||
|
tint="dark"
|
||||||
|
intensity={100}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</BlurView> */}
|
||||||
|
{children}
|
||||||
|
<BackdropBlur blur={4} clip={{ x: 0, y: 128, width: 256, height: 128 }}>
|
||||||
|
<Fill color="rgba(0, 0, 0, 0.2)" />
|
||||||
|
</BackdropBlur>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</Animated.View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default InteractiveBase;
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
"@react-navigation/native": "^6.0.11",
|
"@react-navigation/native": "^6.0.11",
|
||||||
"@react-navigation/native-stack": "^6.7.0",
|
"@react-navigation/native-stack": "^6.7.0",
|
||||||
"@reduxjs/toolkit": "^1.8.3",
|
"@reduxjs/toolkit": "^1.8.3",
|
||||||
|
"@shopify/react-native-skia": "^0.1.208",
|
||||||
"@tanstack/react-query": "^4.2.3",
|
"@tanstack/react-query": "^4.2.3",
|
||||||
"@types/jest": "^28.1.4",
|
"@types/jest": "^28.1.4",
|
||||||
"@types/react-dom": "~18.0.8",
|
"@types/react-dom": "~18.0.8",
|
||||||
@@ -33,7 +34,9 @@
|
|||||||
"add": "^2.0.6",
|
"add": "^2.0.6",
|
||||||
"expo": "^47.0.8",
|
"expo": "^47.0.8",
|
||||||
"expo-asset": "~8.7.0",
|
"expo-asset": "~8.7.0",
|
||||||
|
"expo-blur": "~12.0.1",
|
||||||
"expo-dev-client": "~2.0.1",
|
"expo-dev-client": "~2.0.1",
|
||||||
|
"expo-linear-gradient": "~12.0.1",
|
||||||
"expo-linking": "~3.3.1",
|
"expo-linking": "~3.3.1",
|
||||||
"expo-screen-orientation": "~5.0.1",
|
"expo-screen-orientation": "~5.0.1",
|
||||||
"expo-secure-store": "~12.0.0",
|
"expo-secure-store": "~12.0.0",
|
||||||
|
|||||||
@@ -9,13 +9,15 @@ import TextButton from '../components/TextButton';
|
|||||||
import { useNavigation } from '../Navigation';
|
import { useNavigation } from '../Navigation';
|
||||||
import { string } from 'yup';
|
import { string } from 'yup';
|
||||||
import { FormControl, Input, Stack, Center, Button, Text, Box, useToast } from 'native-base';
|
import { FormControl, Input, Stack, Center, Button, Text, Box, useToast } from 'native-base';
|
||||||
import { TouchableOpacity, Linking, View } from 'react-native'
|
import { TouchableOpacity, Linking, View, StyleSheet } from 'react-native'
|
||||||
import TextFormField from '../components/UI/TextFormField';
|
import TextFormField from '../components/UI/TextFormField';
|
||||||
import LinkBase from '../components/UI/LinkBase';
|
import LinkBase from '../components/UI/LinkBase';
|
||||||
import SeparatorBase from '../components/UI/SeparatorBase';
|
import SeparatorBase from '../components/UI/SeparatorBase';
|
||||||
import ButtonBase from '../components/UI/ButtonBase';
|
import ButtonBase from '../components/UI/ButtonBase';
|
||||||
import { Image, Flex } from 'native-base';
|
import { Image, Flex } from 'native-base';
|
||||||
import ImageBanner from '../assets/banner.jpg';
|
import ImageBanner from '../assets/banner.jpg';
|
||||||
|
import TMPBase from '../components/UI/TMPBase';
|
||||||
|
import { LinearGradient } from 'expo-linear-gradient';
|
||||||
|
|
||||||
const hanldeSignin = async (
|
const hanldeSignin = async (
|
||||||
username: string,
|
username: string,
|
||||||
@@ -76,10 +78,15 @@ const SigninView = () => {
|
|||||||
Continuez avec Google ou entrez vos coordonnées.
|
Continuez avec Google ou entrez vos coordonnées.
|
||||||
</Text>
|
</Text>
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
isOutlined
|
type='outlined'
|
||||||
iconImage='https://upload.wikimedia.org/wikipedia/commons/thumb/5/53/Google_%22G%22_Logo.svg/2008px-Google_%22G%22_Logo.svg.png'
|
iconImage='https://upload.wikimedia.org/wikipedia/commons/thumb/5/53/Google_%22G%22_Logo.svg/2008px-Google_%22G%22_Logo.svg.png'
|
||||||
title="Signin with google"
|
title="Signin with google"
|
||||||
/>
|
/>
|
||||||
|
<ButtonBase
|
||||||
|
type='menu'
|
||||||
|
icon='person'
|
||||||
|
title="Menu"
|
||||||
|
/>
|
||||||
<SeparatorBase>or</SeparatorBase>
|
<SeparatorBase>or</SeparatorBase>
|
||||||
<TextFormField
|
<TextFormField
|
||||||
error={formData.username.error}
|
error={formData.username.error}
|
||||||
@@ -121,6 +128,8 @@ const SigninView = () => {
|
|||||||
</LinkBase>
|
</LinkBase>
|
||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
|
type='outlined'
|
||||||
|
icon='alert'
|
||||||
title="Signin"
|
title="Signin"
|
||||||
isDisabled={
|
isDisabled={
|
||||||
formData.password.error !== null ||
|
formData.password.error !== null ||
|
||||||
@@ -157,8 +166,14 @@ const SigninView = () => {
|
|||||||
style={{width: '100%', height: '100%', borderRadius: 8}}
|
style={{width: '100%', height: '100%', borderRadius: 8}}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
<LinearGradient
|
||||||
|
start={{x: 0, y: 0}}
|
||||||
|
end={{x: 1, y: 1}}
|
||||||
|
colors={['#101014', '#6075F9']}
|
||||||
|
style={{top: 0, bottom: 0, right: 0, left: 0, width: '100%', height: '100%', position: 'absolute', zIndex: -2}}
|
||||||
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SigninView;
|
export default SigninView;
|
||||||
@@ -3549,6 +3549,14 @@
|
|||||||
component-type "^1.2.1"
|
component-type "^1.2.1"
|
||||||
join-component "^1.1.0"
|
join-component "^1.1.0"
|
||||||
|
|
||||||
|
"@shopify/react-native-skia@^0.1.208":
|
||||||
|
version "0.1.208"
|
||||||
|
resolved "https://registry.yarnpkg.com/@shopify/react-native-skia/-/react-native-skia-0.1.208.tgz#f3badb065dc0ed4bbf34a6036c9aa3ded2bfd068"
|
||||||
|
integrity sha512-5Zi6gYlyGo10A1hz2u8RnVP/xzOuRHRAo/HdOY0ncMyKSyvaNtINNfM7zuthRKZT4R3zFF38dYphfC7mcFELtQ==
|
||||||
|
dependencies:
|
||||||
|
canvaskit-wasm "0.38.0"
|
||||||
|
react-reconciler "^0.27.0"
|
||||||
|
|
||||||
"@sideway/address@^4.1.3":
|
"@sideway/address@^4.1.3":
|
||||||
version "4.1.4"
|
version "4.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0"
|
resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0"
|
||||||
@@ -6897,6 +6905,11 @@ caniuse-lite@^1.0.30001125:
|
|||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz#64a0ccef1911a9dcff647115b4430f8eff1ef2d9"
|
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz#64a0ccef1911a9dcff647115b4430f8eff1ef2d9"
|
||||||
integrity sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==
|
integrity sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==
|
||||||
|
|
||||||
|
canvaskit-wasm@0.38.0:
|
||||||
|
version "0.38.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/canvaskit-wasm/-/canvaskit-wasm-0.38.0.tgz#83e6c46f3015c2ff3f6503157f47453af76a7be7"
|
||||||
|
integrity sha512-ZEG6lucpbQ4Ld+mY8C1Ng+PMLVP+/AX02jS0Sdl28NyMxuKSa9uKB8oGd1BYp1XWPyO2Jgr7U8pdyjJ/F3xR5Q==
|
||||||
|
|
||||||
capture-exit@^2.0.0:
|
capture-exit@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4"
|
resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4"
|
||||||
@@ -9056,6 +9069,11 @@ expo-asset@~8.7.0:
|
|||||||
path-browserify "^1.0.0"
|
path-browserify "^1.0.0"
|
||||||
url-parse "^1.5.9"
|
url-parse "^1.5.9"
|
||||||
|
|
||||||
|
expo-blur@~12.0.1:
|
||||||
|
version "12.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/expo-blur/-/expo-blur-12.0.1.tgz#7aa4186620359acfa976dda84360070b634ffe3d"
|
||||||
|
integrity sha512-7oF/xRIFJukM4/qL6ejZ4Z/4YcVExvBPsBrz7rGYz6PtgAkWwYFR62+ExZOzTEG4hgoPPmlnt1ncimsk/MYUgQ==
|
||||||
|
|
||||||
expo-constants@~14.0.0, expo-constants@~14.0.2:
|
expo-constants@~14.0.0, expo-constants@~14.0.2:
|
||||||
version "14.0.2"
|
version "14.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/expo-constants/-/expo-constants-14.0.2.tgz#2cb1dec8f41a64c2fc5b4eecaf77d7661cad01cc"
|
resolved "https://registry.yarnpkg.com/expo-constants/-/expo-constants-14.0.2.tgz#2cb1dec8f41a64c2fc5b4eecaf77d7661cad01cc"
|
||||||
@@ -9126,6 +9144,11 @@ expo-keep-awake@~11.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-11.0.1.tgz#ee354465892a94040ffe09901b85b469e7d54fb3"
|
resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-11.0.1.tgz#ee354465892a94040ffe09901b85b469e7d54fb3"
|
||||||
integrity sha512-44ZjgLE4lnce2d40Pv8xsjMVc6R5GvgHOwZfkLYtGmgYG9TYrEJeEj5UfSeweXPL3pBFhXKfFU8xpGYMaHdP0A==
|
integrity sha512-44ZjgLE4lnce2d40Pv8xsjMVc6R5GvgHOwZfkLYtGmgYG9TYrEJeEj5UfSeweXPL3pBFhXKfFU8xpGYMaHdP0A==
|
||||||
|
|
||||||
|
expo-linear-gradient@~12.0.1:
|
||||||
|
version "12.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/expo-linear-gradient/-/expo-linear-gradient-12.0.1.tgz#452f793b0463ddf313aad431552f23acc85f5d64"
|
||||||
|
integrity sha512-TMl/wBTVQOliL4S3DS5Aa3UFfVySr0mdJEHLG6kfBdMCLkr+tfLI2rGyJ+scS7xgMsvhTIaurhf1+Z0sL3aLCg==
|
||||||
|
|
||||||
expo-linking@~3.3.1:
|
expo-linking@~3.3.1:
|
||||||
version "3.3.1"
|
version "3.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/expo-linking/-/expo-linking-3.3.1.tgz#253b183321e54cb6fa1a667a53d4594aa88a3357"
|
resolved "https://registry.yarnpkg.com/expo-linking/-/expo-linking-3.3.1.tgz#253b183321e54cb6fa1a667a53d4594aa88a3357"
|
||||||
@@ -15911,6 +15934,14 @@ react-query@*:
|
|||||||
broadcast-channel "^3.4.1"
|
broadcast-channel "^3.4.1"
|
||||||
match-sorter "^6.0.2"
|
match-sorter "^6.0.2"
|
||||||
|
|
||||||
|
react-reconciler@^0.27.0:
|
||||||
|
version "0.27.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.27.0.tgz#360124fdf2d76447c7491ee5f0e04503ed9acf5b"
|
||||||
|
integrity sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.1.0"
|
||||||
|
scheduler "^0.21.0"
|
||||||
|
|
||||||
react-redux@^8.0.2:
|
react-redux@^8.0.2:
|
||||||
version "8.0.5"
|
version "8.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.5.tgz#e5fb8331993a019b8aaf2e167a93d10af469c7bd"
|
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.5.tgz#e5fb8331993a019b8aaf2e167a93d10af469c7bd"
|
||||||
@@ -16612,6 +16643,13 @@ scheduler@^0.20.2:
|
|||||||
loose-envify "^1.1.0"
|
loose-envify "^1.1.0"
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
|
|
||||||
|
scheduler@^0.21.0:
|
||||||
|
version "0.21.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.21.0.tgz#6fd2532ff5a6d877b6edb12f00d8ab7e8f308820"
|
||||||
|
integrity sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.1.0"
|
||||||
|
|
||||||
scheduler@^0.22.0:
|
scheduler@^0.22.0:
|
||||||
version "0.22.0"
|
version "0.22.0"
|
||||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.22.0.tgz#83a5d63594edf074add9a7198b1bae76c3db01b8"
|
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.22.0.tgz#83a5d63594edf074add9a7198b1bae76c3db01b8"
|
||||||
|
|||||||
Reference in New Issue
Block a user