@holper/react-native-holper-storybook 0.7.1 → 0.8.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/index.js +2 -3
- package/lib/components/Button/index.js +104 -0
- package/lib/components/Button/{style.ts → style.js} +7 -8
- package/lib/components/Card/index.js +49 -0
- package/lib/components/Card/{style.ts → style.js} +4 -5
- package/lib/components/ConfirmationModal/{index.tsx → index.js} +79 -25
- package/lib/components/ConfirmationModal/{style.tsx → style.js} +13 -14
- package/lib/components/Container/{index.tsx → index.js} +28 -7
- package/lib/components/Container/{style.ts → style.js} +5 -6
- package/lib/components/CustomChatView/{index.tsx → index.js} +30 -22
- package/lib/components/CustomChatView/{style.ts → style.js} +1 -1
- package/lib/components/DeckSwiper/index.js +118 -0
- package/lib/components/DeckSwiper/{style.ts → style.js} +12 -13
- package/lib/components/FlashMessage/index.js +83 -0
- package/lib/components/FloatingContainer/index.js +69 -0
- package/lib/components/FloatingContainer/{style.ts → style.js} +6 -7
- package/lib/components/Footer/index.js +61 -0
- package/lib/components/Footer/{style.ts → style.js} +3 -4
- package/lib/components/Header/index.js +45 -0
- package/lib/components/Header/{style.ts → style.js} +3 -4
- package/lib/components/ImagePicker/{index.tsx → index.js} +12 -3
- package/lib/components/ImageResponsive/index.js +39 -0
- package/lib/components/ImageResponsive/style.js +7 -0
- package/lib/components/ImageViewer/index.js +62 -0
- package/lib/components/ImageViewer/{style.ts → style.js} +3 -4
- package/lib/components/Input/{index.tsx → index.js} +33 -6
- package/lib/components/Input/{style.ts → style.js} +18 -7
- package/lib/components/InputPin/{index.tsx → index.js} +13 -6
- package/lib/components/InputPin/{style.ts → style.js} +6 -7
- package/lib/components/MenuItem/index.js +44 -0
- package/lib/components/MenuItem/{style.ts → style.js} +7 -9
- package/lib/components/NavigationTitle/{index.tsx → index.js} +30 -9
- package/lib/components/NavigationTitle/{style.ts → style.js} +11 -12
- package/lib/components/Notification/index.js +80 -0
- package/lib/components/Notification/{style.ts → style.js} +11 -13
- package/lib/components/PreventDoubleClick/index.js +21 -0
- package/lib/components/Select/index.js +89 -0
- package/lib/components/Select/style.js +81 -0
- package/lib/components/SwipeablePanel/{index.tsx → index.js} +85 -58
- package/lib/components/SwipeablePanel/{style.ts → style.js} +14 -15
- package/lib/components/Switch/index.js +57 -0
- package/lib/components/TakePicture/{confirmPictureModal.tsx → confirmPictureModal.js} +33 -9
- package/lib/components/TakePicture/index.js +198 -0
- package/lib/components/TakePicture/{style.ts → style.js} +4 -4
- package/lib/components/Text/index.js +75 -0
- package/lib/components/Text/{style.ts → style.js} +2 -4
- package/lib/components/Textarea/{index.tsx → index.js} +24 -5
- package/lib/components/Textarea/{style.ts → style.js} +4 -5
- package/lib/components/TimeOutButton/index.js +104 -0
- package/lib/components/TimeOutButton/{style.ts → style.js} +3 -4
- package/lib/components/UploadDocument/index.js +222 -0
- package/lib/components/UploadDocument/{style.ts → style.js} +15 -16
- package/lib/components/VirtualKeyboard/index.js +86 -0
- package/lib/components/VirtualKeyboard/{style.ts → style.js} +8 -9
- package/lib/components/index.js +28 -0
- package/lib/configs/constants.js +276 -0
- package/lib/configs/loadFonts.js +11 -0
- package/lib/hooks/index.js +1 -0
- package/lib/hooks/{useDebounce.tsx → useDebounce.js} +4 -6
- package/lib/index.js +2 -3
- package/package.json +58 -72
- package/{README.md → readme.md} +20 -19
- package/LICENSE +0 -21
- package/lib/components/Button/index.tsx +0 -66
- package/lib/components/Card/index.tsx +0 -33
- package/lib/components/DeckSwiper/index.tsx +0 -90
- package/lib/components/DonutCountdown/index.tsx +0 -86
- package/lib/components/DonutCountdown/style.ts +0 -8
- package/lib/components/FloatingContainer/index.tsx +0 -35
- package/lib/components/Footer/index.tsx +0 -35
- package/lib/components/Header/index.tsx +0 -21
- package/lib/components/ImageResponsive/index.tsx +0 -24
- package/lib/components/ImageResponsive/style.ts +0 -9
- package/lib/components/ImageViewer/index.tsx +0 -36
- package/lib/components/MenuItem/index.tsx +0 -25
- package/lib/components/Notification/index.tsx +0 -44
- package/lib/components/PreventDoubleClick/index.tsx +0 -28
- package/lib/components/Select/index.tsx +0 -51
- package/lib/components/Select/style.ts +0 -64
- package/lib/components/Switch/index.tsx +0 -30
- package/lib/components/TakePicture/index.tsx +0 -148
- package/lib/components/Text/index.tsx +0 -33
- package/lib/components/TimeOutButton/index.tsx +0 -67
- package/lib/components/Toast/index.tsx +0 -34
- package/lib/components/Toast/style.ts +0 -12
- package/lib/components/UploadDocument/index.tsx +0 -179
- package/lib/components/VirtualKeyboard/index.tsx +0 -75
- package/lib/components/index.ts +0 -29
- package/lib/configs/constants.ts +0 -273
- package/lib/configs/types.ts +0 -326
- package/lib/hooks/index.ts +0 -2
- package/lib/hooks/useLoadFonts.tsx +0 -13
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
import { ActivityIndicator, TouchableOpacity } from 'react-native';
|
|
3
|
-
|
|
4
|
-
import { Colors } from '../../configs/constants';
|
|
5
|
-
import withPreventDoubleClick from './../PreventDoubleClick';
|
|
6
|
-
import style from './style';
|
|
7
|
-
|
|
8
|
-
import type { ButtonProps } from '../../configs/types';
|
|
9
|
-
|
|
10
|
-
const Button = ({
|
|
11
|
-
onPress,
|
|
12
|
-
disabled,
|
|
13
|
-
isLoading,
|
|
14
|
-
bordered,
|
|
15
|
-
variant = 'primary',
|
|
16
|
-
size = 'medium',
|
|
17
|
-
noShadow,
|
|
18
|
-
style: customStyle,
|
|
19
|
-
debounceDelay = 0,
|
|
20
|
-
children,
|
|
21
|
-
}: ButtonProps) => {
|
|
22
|
-
const [isDisabled, setIsDisabled] = useState<boolean>(disabled || false);
|
|
23
|
-
|
|
24
|
-
useEffect(() => setIsDisabled(disabled || false), [disabled]);
|
|
25
|
-
|
|
26
|
-
const getSpinnerColor = () => {
|
|
27
|
-
switch (variant) {
|
|
28
|
-
case 'primary':
|
|
29
|
-
case 'inverted':
|
|
30
|
-
case 'error':
|
|
31
|
-
return Colors.white;
|
|
32
|
-
default:
|
|
33
|
-
return Colors.darkblue;
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const handleTap = () => {
|
|
38
|
-
if (onPress) {
|
|
39
|
-
onPress();
|
|
40
|
-
}
|
|
41
|
-
setIsDisabled(true);
|
|
42
|
-
setTimeout(() => {
|
|
43
|
-
setIsDisabled(false);
|
|
44
|
-
}, debounceDelay);
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<TouchableOpacity
|
|
49
|
-
style={[
|
|
50
|
-
style.button,
|
|
51
|
-
style[variant],
|
|
52
|
-
style[size],
|
|
53
|
-
bordered ? style.bordered : {},
|
|
54
|
-
isDisabled ? style.disabled : {},
|
|
55
|
-
noShadow ? style.noShadow : {},
|
|
56
|
-
customStyle,
|
|
57
|
-
]}
|
|
58
|
-
disabled={isLoading || isDisabled}
|
|
59
|
-
onPress={handleTap}
|
|
60
|
-
>
|
|
61
|
-
{isLoading ? <ActivityIndicator color={getSpinnerColor()} size={28} /> : children}
|
|
62
|
-
</TouchableOpacity>
|
|
63
|
-
);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export default withPreventDoubleClick(Button);
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { TouchableOpacityProps, ViewProps } from 'react-native';
|
|
2
|
-
|
|
3
|
-
import { TouchableOpacity, View } from 'react-native';
|
|
4
|
-
|
|
5
|
-
import withPreventDoubleClick from '../PreventDoubleClick';
|
|
6
|
-
import style from './style';
|
|
7
|
-
|
|
8
|
-
import type { CardProps } from '../../configs/types';
|
|
9
|
-
|
|
10
|
-
const TappedTouchableOpacity = withPreventDoubleClick(TouchableOpacity);
|
|
11
|
-
|
|
12
|
-
const Card = (
|
|
13
|
-
{ children, isButton, onPress, noShadow, style: customStyle }: CardProps,
|
|
14
|
-
...props: (TouchableOpacityProps & ViewProps)[]
|
|
15
|
-
) => (
|
|
16
|
-
<>
|
|
17
|
-
{isButton ? (
|
|
18
|
-
<TappedTouchableOpacity
|
|
19
|
-
onPress={onPress}
|
|
20
|
-
style={[style.card, customStyle, noShadow ? style.noShadow : {}]}
|
|
21
|
-
{...props}
|
|
22
|
-
>
|
|
23
|
-
{children}
|
|
24
|
-
</TappedTouchableOpacity>
|
|
25
|
-
) : (
|
|
26
|
-
<View style={[style.card, customStyle, noShadow ? style.noShadow : {}]} {...props}>
|
|
27
|
-
{children}
|
|
28
|
-
</View>
|
|
29
|
-
)}
|
|
30
|
-
</>
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
export default Card;
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { Entypo } from '@expo/vector-icons';
|
|
2
|
-
import { useRef, useState } from 'react';
|
|
3
|
-
import { Image, View } from 'react-native';
|
|
4
|
-
import Swiper from 'react-native-deck-swiper';
|
|
5
|
-
|
|
6
|
-
import { Colors } from '../../configs/constants';
|
|
7
|
-
import Button from '../Button';
|
|
8
|
-
import Text from '../Text';
|
|
9
|
-
import style from './style';
|
|
10
|
-
|
|
11
|
-
import type { DeckSwiperProps } from '../../configs/types';
|
|
12
|
-
|
|
13
|
-
const DeckSwiper = ({ data = [], inverted, nextText, onChange, onFinish }: DeckSwiperProps) => {
|
|
14
|
-
const swiper = useRef<Swiper<(typeof data)[0]>>(null);
|
|
15
|
-
const [finished, setFinished] = useState(false);
|
|
16
|
-
const [index, setIndex] = useState(0);
|
|
17
|
-
|
|
18
|
-
const renderDots = () =>
|
|
19
|
-
data?.map((d, i) => (
|
|
20
|
-
<Entypo name="dot-single" size={36} key={`dot-${i}`} style={style[index === i ? 'dotSelected' : 'dot']} />
|
|
21
|
-
));
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<>
|
|
25
|
-
<Swiper
|
|
26
|
-
ref={swiper}
|
|
27
|
-
cards={data}
|
|
28
|
-
renderCard={(card) => {
|
|
29
|
-
if (!card) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
return (
|
|
33
|
-
<View style={style.card}>
|
|
34
|
-
<View style={style.imageContainer}>
|
|
35
|
-
<Image
|
|
36
|
-
style={style.imageResponsive}
|
|
37
|
-
source={card.image}
|
|
38
|
-
progressiveRenderingEnabled
|
|
39
|
-
resizeMode="contain"
|
|
40
|
-
/>
|
|
41
|
-
</View>
|
|
42
|
-
<View style={style.textContainer}>
|
|
43
|
-
<Text size="extra-large" style={style.title}>
|
|
44
|
-
{card.title}
|
|
45
|
-
</Text>
|
|
46
|
-
<Text size="large" align="center">
|
|
47
|
-
{card.description}
|
|
48
|
-
</Text>
|
|
49
|
-
</View>
|
|
50
|
-
</View>
|
|
51
|
-
);
|
|
52
|
-
}}
|
|
53
|
-
onSwipedAll={() => {
|
|
54
|
-
setFinished(true);
|
|
55
|
-
if (onFinish) {
|
|
56
|
-
onFinish();
|
|
57
|
-
}
|
|
58
|
-
}}
|
|
59
|
-
onSwipedRight={(i) => {
|
|
60
|
-
setIndex(i - 1);
|
|
61
|
-
onChange?.(i - 1);
|
|
62
|
-
}}
|
|
63
|
-
onSwipedLeft={(i) => {
|
|
64
|
-
setIndex(i + 1);
|
|
65
|
-
onChange?.(i + 1);
|
|
66
|
-
}}
|
|
67
|
-
cardIndex={index}
|
|
68
|
-
backgroundColor={Colors.white}
|
|
69
|
-
stackSize={2}
|
|
70
|
-
verticalSwipe={false}
|
|
71
|
-
showSecondCard
|
|
72
|
-
disableRightSwipe={index === 0}
|
|
73
|
-
goBackToPreviousCardOnSwipeRight
|
|
74
|
-
childrenOnTop
|
|
75
|
-
/>
|
|
76
|
-
{!finished && (
|
|
77
|
-
<>
|
|
78
|
-
<View style={style.dotsContainer}>{renderDots()}</View>
|
|
79
|
-
<View style={style.container}>
|
|
80
|
-
<Button variant={inverted ? 'inverted' : 'primary'} onPress={() => swiper.current?.swipeLeft()}>
|
|
81
|
-
<Text color="white">{nextText}</Text>
|
|
82
|
-
</Button>
|
|
83
|
-
</View>
|
|
84
|
-
</>
|
|
85
|
-
)}
|
|
86
|
-
</>
|
|
87
|
-
);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export default DeckSwiper;
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { Animated, StyleSheet, View } from 'react-native';
|
|
3
|
-
import Svg, { Circle } from 'react-native-svg';
|
|
4
|
-
|
|
5
|
-
import { Colors } from '../../configs/constants';
|
|
6
|
-
import Text from '../Text';
|
|
7
|
-
import styles from './style';
|
|
8
|
-
|
|
9
|
-
import type { DonutCountdownProps } from '../../configs/types';
|
|
10
|
-
|
|
11
|
-
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
|
|
12
|
-
|
|
13
|
-
const DonutCountdown = ({
|
|
14
|
-
bgColor = Colors.dimgray,
|
|
15
|
-
color = Colors.green,
|
|
16
|
-
duration = 10,
|
|
17
|
-
onComplete = () => {},
|
|
18
|
-
radius = 60,
|
|
19
|
-
strokeWidth = 10,
|
|
20
|
-
textColor = Colors.darkgray,
|
|
21
|
-
textSize = 'medium',
|
|
22
|
-
}: DonutCountdownProps) => {
|
|
23
|
-
const circumference = 2 * Math.PI * radius;
|
|
24
|
-
const halfCircle = radius + strokeWidth;
|
|
25
|
-
const animatedValue = useRef(new Animated.Value(0)).current;
|
|
26
|
-
const [timeLeft, setTimeLeft] = useState(duration);
|
|
27
|
-
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
// Animate from 0 to 1
|
|
30
|
-
Animated.timing(animatedValue, {
|
|
31
|
-
toValue: 1,
|
|
32
|
-
duration: duration * 1000,
|
|
33
|
-
useNativeDriver: true,
|
|
34
|
-
}).start(onComplete);
|
|
35
|
-
|
|
36
|
-
// Countdown timer
|
|
37
|
-
const interval = setInterval(() => {
|
|
38
|
-
setTimeLeft((prev) => {
|
|
39
|
-
if (prev <= 1) {
|
|
40
|
-
clearInterval(interval);
|
|
41
|
-
return 0;
|
|
42
|
-
}
|
|
43
|
-
return prev - 1;
|
|
44
|
-
});
|
|
45
|
-
}, 1000);
|
|
46
|
-
|
|
47
|
-
return () => clearInterval(interval);
|
|
48
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
49
|
-
}, []);
|
|
50
|
-
|
|
51
|
-
const strokeDashoffset = animatedValue.interpolate({
|
|
52
|
-
inputRange: [0, 1],
|
|
53
|
-
outputRange: [0, circumference],
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
return (
|
|
57
|
-
<View style={{ width: radius * 2, height: radius * 2 }}>
|
|
58
|
-
<Svg width={radius * 2} height={radius * 2} viewBox={`0 0 ${halfCircle * 2} ${halfCircle * 2}`}>
|
|
59
|
-
{/* Background circle */}
|
|
60
|
-
<Circle cx="50%" cy="50%" r={radius} stroke={bgColor} strokeWidth={strokeWidth} fill="none" />
|
|
61
|
-
{/* Animated circle */}
|
|
62
|
-
<AnimatedCircle
|
|
63
|
-
cx="50%"
|
|
64
|
-
cy="50%"
|
|
65
|
-
r={radius}
|
|
66
|
-
stroke={color}
|
|
67
|
-
strokeWidth={strokeWidth}
|
|
68
|
-
fill="none"
|
|
69
|
-
strokeDasharray={`${circumference}, ${circumference}`}
|
|
70
|
-
strokeDashoffset={strokeDashoffset}
|
|
71
|
-
strokeLinecap="round"
|
|
72
|
-
transform={`rotate(-90 ${halfCircle} ${halfCircle})`}
|
|
73
|
-
/>
|
|
74
|
-
</Svg>
|
|
75
|
-
|
|
76
|
-
{/* Centered countdown text */}
|
|
77
|
-
<View style={[StyleSheet.absoluteFillObject, styles.center]}>
|
|
78
|
-
<Text weight="semiBold" size={textSize} style={{ color: textColor }}>
|
|
79
|
-
{timeLeft}
|
|
80
|
-
</Text>
|
|
81
|
-
</View>
|
|
82
|
-
</View>
|
|
83
|
-
);
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
export default DonutCountdown;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { KeyboardAvoidingView, Platform, RefreshControl, ScrollView, View } from 'react-native';
|
|
2
|
-
|
|
3
|
-
import style from './style';
|
|
4
|
-
|
|
5
|
-
import type { FloatingContainerProps } from '../../configs/types';
|
|
6
|
-
|
|
7
|
-
const FloatingContainer = ({
|
|
8
|
-
useRefreshControl,
|
|
9
|
-
onRefresh,
|
|
10
|
-
isRefreshing,
|
|
11
|
-
children,
|
|
12
|
-
floatingComponent,
|
|
13
|
-
centered,
|
|
14
|
-
floatingContainerStyle,
|
|
15
|
-
disableScroll,
|
|
16
|
-
}: FloatingContainerProps) => (
|
|
17
|
-
<KeyboardAvoidingView style={style.floatingContainer} behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
|
|
18
|
-
<ScrollView
|
|
19
|
-
contentContainerStyle={centered ? style.centered : {}}
|
|
20
|
-
fadingEdgeLength={150}
|
|
21
|
-
keyboardShouldPersistTaps="handled"
|
|
22
|
-
showsVerticalScrollIndicator={false}
|
|
23
|
-
scrollEnabled={!disableScroll}
|
|
24
|
-
keyboardDismissMode="on-drag"
|
|
25
|
-
refreshControl={
|
|
26
|
-
useRefreshControl ? <RefreshControl refreshing={!!isRefreshing} onRefresh={onRefresh} /> : undefined
|
|
27
|
-
}
|
|
28
|
-
>
|
|
29
|
-
{children}
|
|
30
|
-
</ScrollView>
|
|
31
|
-
<View style={[style.container, floatingContainerStyle]}>{floatingComponent}</View>
|
|
32
|
-
</KeyboardAvoidingView>
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
export default FloatingContainer;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { Ionicons } from '@expo/vector-icons';
|
|
2
|
-
import { TouchableOpacity, View } from 'react-native';
|
|
3
|
-
|
|
4
|
-
import { Colors } from '../../configs/constants';
|
|
5
|
-
import Text from '../Text';
|
|
6
|
-
import style from './style';
|
|
7
|
-
|
|
8
|
-
import type { FooterProps } from '../../configs/types';
|
|
9
|
-
|
|
10
|
-
const Footer = ({ inverted, tabs }: FooterProps) => {
|
|
11
|
-
const renderTab = () =>
|
|
12
|
-
tabs.map((tab, index) => (
|
|
13
|
-
<TouchableOpacity key={`tab-${index}`} style={style.tab} onPress={tab.onPress}>
|
|
14
|
-
<Ionicons
|
|
15
|
-
name={tab.icon as keyof typeof Ionicons.glyphMap}
|
|
16
|
-
size={20}
|
|
17
|
-
color={inverted ? Colors.white : Colors.darkblue}
|
|
18
|
-
/>
|
|
19
|
-
<Text color={inverted ? 'white' : 'dark'} size="small">
|
|
20
|
-
{tab.text}
|
|
21
|
-
</Text>
|
|
22
|
-
{tab.badge && tab.badge > 0 && (
|
|
23
|
-
<View style={style.badge}>
|
|
24
|
-
<Text color="white" size="tiny" weight="semiBold" align="center">
|
|
25
|
-
{tab.badge > 9 ? '+9' : tab.badge}
|
|
26
|
-
</Text>
|
|
27
|
-
</View>
|
|
28
|
-
)}
|
|
29
|
-
</TouchableOpacity>
|
|
30
|
-
));
|
|
31
|
-
|
|
32
|
-
return <View style={[style.footerContainer, style[inverted ? 'inverted' : 'default']]}>{renderTab()}</View>;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export default Footer;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Ionicons } from '@expo/vector-icons';
|
|
2
|
-
import { Image, TouchableOpacity, View } from 'react-native';
|
|
3
|
-
|
|
4
|
-
import { Colors } from '../../configs/constants';
|
|
5
|
-
import style from './style';
|
|
6
|
-
|
|
7
|
-
import type { HeaderProps } from '../../configs/types';
|
|
8
|
-
|
|
9
|
-
const Header = ({ inverted, logo, right, onMenuPress }: HeaderProps) => (
|
|
10
|
-
<View style={[style.headerContainer, style[inverted ? 'inverted' : 'default']]}>
|
|
11
|
-
<TouchableOpacity onPress={onMenuPress}>
|
|
12
|
-
<Ionicons name="menu-outline" size={30} color={inverted ? Colors.white : Colors.darkblue} />
|
|
13
|
-
</TouchableOpacity>
|
|
14
|
-
<View style={style.imageContainer}>
|
|
15
|
-
<Image style={style.imageResponsive} source={logo} progressiveRenderingEnabled resizeMode="contain" />
|
|
16
|
-
</View>
|
|
17
|
-
{right}
|
|
18
|
-
</View>
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
export default Header;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
|
-
import { Image, View } from 'react-native';
|
|
3
|
-
|
|
4
|
-
import style from './style';
|
|
5
|
-
|
|
6
|
-
import type { ImageResponsiveProps } from '../../configs/types';
|
|
7
|
-
|
|
8
|
-
const ImageResponsive = ({ source, style: customStyle, avatar, ...props }: ImageResponsiveProps) => {
|
|
9
|
-
const [width, setWidth] = useState<number>(100);
|
|
10
|
-
|
|
11
|
-
return (
|
|
12
|
-
<View style={[customStyle, avatar ? { borderRadius: width / 2, overflow: 'hidden' } : {}]}>
|
|
13
|
-
<Image
|
|
14
|
-
style={style.responsiveImage}
|
|
15
|
-
source={source}
|
|
16
|
-
resizeMode={avatar ? 'cover' : 'contain'}
|
|
17
|
-
onLayout={({ nativeEvent }) => setWidth(nativeEvent.layout.width)}
|
|
18
|
-
{...props}
|
|
19
|
-
/>
|
|
20
|
-
</View>
|
|
21
|
-
);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export default ImageResponsive;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { Ionicons } from '@expo/vector-icons';
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { ActivityIndicator, Modal, TouchableOpacity, View } from 'react-native';
|
|
4
|
-
|
|
5
|
-
import { Colors } from '../../configs/constants';
|
|
6
|
-
import ImageResponsive from '../ImageResponsive';
|
|
7
|
-
import style from './style';
|
|
8
|
-
|
|
9
|
-
import type { ImageViewerProps } from '../../configs/types';
|
|
10
|
-
|
|
11
|
-
const ImageViewer = ({ source, style: imageStyle, ...props }: ImageViewerProps) => {
|
|
12
|
-
const [loading, setLoading] = useState<boolean>(true);
|
|
13
|
-
const [visible, setVisible] = useState<boolean>(false);
|
|
14
|
-
|
|
15
|
-
return (
|
|
16
|
-
<>
|
|
17
|
-
<TouchableOpacity onPress={() => setVisible(true)}>
|
|
18
|
-
<ImageResponsive source={source} style={imageStyle} {...props} />
|
|
19
|
-
</TouchableOpacity>
|
|
20
|
-
|
|
21
|
-
<Modal animationType="slide" transparent visible={visible} onRequestClose={() => {}}>
|
|
22
|
-
<View style={style.container}>
|
|
23
|
-
<TouchableOpacity onPress={() => setVisible(false)} style={style.closeIcon}>
|
|
24
|
-
<Ionicons name="close-outline" size={24} color={Colors.darkblue} />
|
|
25
|
-
</TouchableOpacity>
|
|
26
|
-
|
|
27
|
-
<ImageResponsive source={source} style={style.body} onLoadEnd={() => setLoading(false)} />
|
|
28
|
-
|
|
29
|
-
{loading && <ActivityIndicator style={style.activityIndicator} />}
|
|
30
|
-
</View>
|
|
31
|
-
</Modal>
|
|
32
|
-
</>
|
|
33
|
-
);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export default ImageViewer;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Feather } from '@expo/vector-icons';
|
|
2
|
-
import { TouchableOpacity, View } from 'react-native';
|
|
3
|
-
|
|
4
|
-
import { Colors } from '../../configs/constants';
|
|
5
|
-
import Text from '../Text';
|
|
6
|
-
import style from './style';
|
|
7
|
-
|
|
8
|
-
import type { MenuItemProps } from '../../configs/types';
|
|
9
|
-
|
|
10
|
-
const MenuItem = ({ icon, text, disabled, onPress, last }: MenuItemProps) => (
|
|
11
|
-
<TouchableOpacity
|
|
12
|
-
style={[style.menuItem, last ? style.last : {}, disabled ? style.disabled : {}]}
|
|
13
|
-
onPress={onPress}
|
|
14
|
-
disabled={disabled}
|
|
15
|
-
>
|
|
16
|
-
<View style={style.left}>
|
|
17
|
-
{icon}
|
|
18
|
-
<Text style={style.text}>{text}</Text>
|
|
19
|
-
</View>
|
|
20
|
-
|
|
21
|
-
<Feather name="chevron-right" size={16} color={Colors.darkblue} style={style.rightIcon} />
|
|
22
|
-
</TouchableOpacity>
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
export default MenuItem;
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { Ionicons } from '@expo/vector-icons';
|
|
2
|
-
import dayjs from 'dayjs';
|
|
3
|
-
import relativeTime from 'dayjs/plugin/relativeTime';
|
|
4
|
-
import { TouchableOpacity, View } from 'react-native';
|
|
5
|
-
|
|
6
|
-
import { Colors } from '../../configs/constants';
|
|
7
|
-
import ImageResponsive from '../ImageResponsive';
|
|
8
|
-
import Text from '../Text';
|
|
9
|
-
import style from './style';
|
|
10
|
-
|
|
11
|
-
import type { NotificationProps } from '../../configs/types';
|
|
12
|
-
|
|
13
|
-
dayjs.extend(relativeTime);
|
|
14
|
-
|
|
15
|
-
const Notification = ({
|
|
16
|
-
first,
|
|
17
|
-
active,
|
|
18
|
-
hideAvatar,
|
|
19
|
-
avatar,
|
|
20
|
-
title,
|
|
21
|
-
description,
|
|
22
|
-
date = dayjs().fromNow(),
|
|
23
|
-
onPress,
|
|
24
|
-
}: NotificationProps) => (
|
|
25
|
-
<TouchableOpacity style={[style.container, first ? style.first : {}, active ? style.active : {}]} onPress={onPress}>
|
|
26
|
-
{!hideAvatar && <ImageResponsive source={avatar} avatar style={style.avatar} />}
|
|
27
|
-
<View style={style.textContainer}>
|
|
28
|
-
<View style={style.text}>
|
|
29
|
-
<View style={style.textInner}>
|
|
30
|
-
<Text weight="semiBold">{title}</Text>
|
|
31
|
-
{active && <Ionicons name="ellipse" color={Colors.green} size={12} style={style.icon} />}
|
|
32
|
-
</View>
|
|
33
|
-
<Text color="light" size="tiny" style={style.time}>
|
|
34
|
-
{dayjs(date).fromNow()}
|
|
35
|
-
</Text>
|
|
36
|
-
</View>
|
|
37
|
-
<Text color="light" size="small" ellipsizeMode="tail" numberOfLines={3}>
|
|
38
|
-
{description}
|
|
39
|
-
</Text>
|
|
40
|
-
</View>
|
|
41
|
-
</TouchableOpacity>
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
export default Notification;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { ComponentType } from 'react';
|
|
2
|
-
|
|
3
|
-
import { debounce } from 'lodash';
|
|
4
|
-
import { PureComponent } from 'react';
|
|
5
|
-
|
|
6
|
-
import type { withPreventDoubleClickProps } from '../../configs/types';
|
|
7
|
-
|
|
8
|
-
function withPreventDoubleClick<P extends withPreventDoubleClickProps>(WrappedComponent: ComponentType<P>) {
|
|
9
|
-
class PreventDoubleClick extends PureComponent<P> {
|
|
10
|
-
debouncedOnPress = () => {
|
|
11
|
-
if (this.props.onPress) {
|
|
12
|
-
this.props.onPress();
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
onPress = debounce(this.debouncedOnPress, 300, { leading: true, trailing: false });
|
|
17
|
-
static displayName: string;
|
|
18
|
-
|
|
19
|
-
render() {
|
|
20
|
-
return <WrappedComponent {...this.props} onPress={this.onPress} />;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
PreventDoubleClick.displayName = `withPreventDoubleClick(${WrappedComponent.displayName || WrappedComponent.name})`;
|
|
25
|
-
return PreventDoubleClick;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export default withPreventDoubleClick;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { Feather } from '@expo/vector-icons';
|
|
2
|
-
import { View } from 'react-native';
|
|
3
|
-
import RNPickerSelect from 'react-native-picker-select';
|
|
4
|
-
|
|
5
|
-
import style from './style';
|
|
6
|
-
|
|
7
|
-
import type { SelectProps } from '../../configs/types';
|
|
8
|
-
|
|
9
|
-
const Select = ({
|
|
10
|
-
disabled,
|
|
11
|
-
fitToContainer,
|
|
12
|
-
items = [],
|
|
13
|
-
onValueChange,
|
|
14
|
-
placeholder,
|
|
15
|
-
value = '',
|
|
16
|
-
variant = 'default',
|
|
17
|
-
}: SelectProps) => (
|
|
18
|
-
<View style={[style.container, disabled ? style.disabled : {}, fitToContainer ? style.fit : {}]}>
|
|
19
|
-
<RNPickerSelect
|
|
20
|
-
value={value}
|
|
21
|
-
onValueChange={(val) => onValueChange?.(val)}
|
|
22
|
-
disabled={disabled}
|
|
23
|
-
placeholder={{
|
|
24
|
-
label: placeholder,
|
|
25
|
-
value: '',
|
|
26
|
-
color: style.placeholderStyle.color,
|
|
27
|
-
}}
|
|
28
|
-
items={items}
|
|
29
|
-
Icon={() => <Feather name="chevron-down" size={24} style={style.iconStyle} />}
|
|
30
|
-
useNativeAndroidPickerStyle={false}
|
|
31
|
-
pickerProps={{ mode: 'dropdown', enabled: !disabled, itemStyle: style.itemStyle }}
|
|
32
|
-
style={{
|
|
33
|
-
inputIOSContainer: { pointerEvents: 'none', ...style.basicStyle, ...style[`${variant}Container`] },
|
|
34
|
-
inputAndroidContainer: { ...style.basicStyle, ...style[`${variant}Container`] },
|
|
35
|
-
inputIOS: {
|
|
36
|
-
...style.fontStyle,
|
|
37
|
-
...(variant === 'error' ? style.errorFontStyle : {}),
|
|
38
|
-
},
|
|
39
|
-
inputAndroid: {
|
|
40
|
-
...style.fontStyle,
|
|
41
|
-
...(variant === 'error' ? style.errorFontStyle : {}),
|
|
42
|
-
},
|
|
43
|
-
placeholder: style.placeholderStyle,
|
|
44
|
-
chevronUp: style.selectIcon,
|
|
45
|
-
chevronDown: style.selectIcon,
|
|
46
|
-
}}
|
|
47
|
-
/>
|
|
48
|
-
</View>
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
export default Select;
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { Dimensions, StyleSheet } from 'react-native';
|
|
2
|
-
|
|
3
|
-
import { borderRadius, Colors } from '../../configs/constants';
|
|
4
|
-
|
|
5
|
-
const { width } = Dimensions.get('window');
|
|
6
|
-
|
|
7
|
-
export default StyleSheet.create({
|
|
8
|
-
container: {
|
|
9
|
-
width: width - 60,
|
|
10
|
-
position: 'relative',
|
|
11
|
-
},
|
|
12
|
-
fit: {
|
|
13
|
-
width: '100%',
|
|
14
|
-
position: 'relative',
|
|
15
|
-
},
|
|
16
|
-
selectIcon: {
|
|
17
|
-
marginTop: 20,
|
|
18
|
-
marginRight: 15,
|
|
19
|
-
},
|
|
20
|
-
disabled: {
|
|
21
|
-
opacity: 0.5,
|
|
22
|
-
},
|
|
23
|
-
basicStyle: {
|
|
24
|
-
height: 50,
|
|
25
|
-
width: '100%',
|
|
26
|
-
borderRadius,
|
|
27
|
-
borderWidth: 1,
|
|
28
|
-
paddingHorizontal: 10,
|
|
29
|
-
backgroundColor: Colors.white,
|
|
30
|
-
marginVertical: 6,
|
|
31
|
-
},
|
|
32
|
-
defaultContainer: {
|
|
33
|
-
borderColor: Colors.midblue,
|
|
34
|
-
},
|
|
35
|
-
completedContainer: {
|
|
36
|
-
borderColor: Colors.green,
|
|
37
|
-
},
|
|
38
|
-
errorContainer: {
|
|
39
|
-
borderColor: Colors.red,
|
|
40
|
-
},
|
|
41
|
-
fontStyle: {
|
|
42
|
-
flex: 1,
|
|
43
|
-
color: Colors.darkblue,
|
|
44
|
-
fontFamily: 'poppins_regular',
|
|
45
|
-
},
|
|
46
|
-
errorFontStyle: {
|
|
47
|
-
color: Colors.red,
|
|
48
|
-
},
|
|
49
|
-
placeholderStyle: {
|
|
50
|
-
fontSize: 14,
|
|
51
|
-
fontFamily: 'poppins_regular',
|
|
52
|
-
color: Colors.midblue,
|
|
53
|
-
},
|
|
54
|
-
iconStyle: {
|
|
55
|
-
marginRight: 10,
|
|
56
|
-
marginTop: 12,
|
|
57
|
-
color: Colors.darkblue,
|
|
58
|
-
},
|
|
59
|
-
itemStyle: {
|
|
60
|
-
color: Colors.darkblue,
|
|
61
|
-
fontFamily: 'poppins_regular',
|
|
62
|
-
fontSize: 16,
|
|
63
|
-
},
|
|
64
|
-
});
|