diff --git a/app.json b/app.json index 6ea4409..8cfd296 100644 --- a/app.json +++ b/app.json @@ -12,6 +12,10 @@ "resizeMode": "contain", "backgroundColor": "#ffffff" }, + "updates": { + "fallbackToCacheTimeout": 10000, + // "url": "https://u.expo.dev/f4b56fb1-b6cc-4fb3-aeb8-2443be51c4dc" + }, "assetBundlePatterns": ["**/*"], "ios": { // "supportsTablet": true, diff --git a/app/(auth)/Reset.tsx b/app/(auth)/Reset.tsx index 17ab7f5..f6f7e1f 100644 --- a/app/(auth)/Reset.tsx +++ b/app/(auth)/Reset.tsx @@ -1,46 +1,5 @@ -import React, { useState } from 'react'; -import { router } from 'expo-router'; -import { validateEmail } from '@/validations/validateEmail'; -import Background from '@/widgets/Background'; -import BackButton from '@/widgets/BackButton'; -import Logo from '@/widgets/Logo'; -import Header from '@/widgets/Header'; -import TextInput from '@/widgets/TextInput'; -import Button from '@/widgets/Button'; +import Reset from '@/boards/Reset'; -export default function ResetPasswordScreen() { - const [email, setEmail] = useState({ value: '', error: '' }); - - const sendResetPasswordEmail = () => { - const emailError = validateEmail(email.value); - if (emailError) { - setEmail({ ...email, error: emailError }); - return; - } - router.push('/Login'); - }; - - return ( - - - -
Reset your password.
- setEmail({ value: text, error: '' })} - error={!!email.error} - errorText={email.error} - autoCapitalize='none' - autoCompleteType='email' - textContentType='emailAddress' - keyboardType='email-address' - description='You will receive an email with the reset link.' - /> - -
- ); +export default function Reset_Route() { + return } diff --git a/app/(main)/Home.tsx b/app/(main)/Home.tsx index bcece22..2bdb4e7 100644 --- a/app/(main)/Home.tsx +++ b/app/(main)/Home.tsx @@ -1,66 +1,5 @@ -import executeAuth from "@/events/executeAuth"; -import Background from "@/widgets/Background"; -import Button from "@/widgets/Button"; -import Header from "@/widgets/Header"; -import Logo from "@/widgets/Logo"; -import Paragraph from "@/widgets/Paragraph"; -import Snackbar from "@/widgets/Snackbar"; -import { useState } from "react"; +import Home from '@/boards/Home'; -import { bottom } from "bottoms"; -import { router } from "expo-router"; - -import SomeComponent from "@/components/SomeComponent"; - -export default function Home() { - - const [error, setError] = useState('') - - const { executeLogout } = executeAuth(); - - const logout = async () => { - try { - await executeLogout() - } catch (error : any ){ - setError(error.message) - } - } - - const openModal = () => { - bottom.open('Two'); - } - const openModal2 = () => { - bottom.open('Two'); - } - const data = { - '1':'293' - } - - return ( - - {/* */} -
Home
- Expo Router Test - router.push('/(modal)/Modal') - - Navigate to Modal Directly - router.push('/(modal)/Modal') - - {/* - - - - 0} /> */} -
- ); +export default function Home_Route() { + return } diff --git a/app/(main)/List.tsx b/app/(main)/List.tsx index 71270e8..c6b73cf 100644 --- a/app/(main)/List.tsx +++ b/app/(main)/List.tsx @@ -2,13 +2,10 @@ import { StyleSheet, Text, View } from 'react-native' import React from 'react' import Background from '@/widgets/Background' import Header from '@/widgets/Header'; +import ExampleAnimated from '@/boards/ExampleAnimated'; export default function ListRoute(): React.JSX.Element { - return ( - -
Second Tab
-
- ); + return } const styles = StyleSheet.create({}) \ No newline at end of file diff --git a/app/(main)/Tiktok.tsx b/app/(main)/Tiktok.tsx new file mode 100644 index 0000000..589647a --- /dev/null +++ b/app/(main)/Tiktok.tsx @@ -0,0 +1,5 @@ +import ExampleTiktok from '@/boards/ExampleTiktok'; + +export default function Home_Route() { + return ; +} diff --git a/app/(main)/_layout.tsx b/app/(main)/_layout.tsx index 712b4dc..fcd136e 100644 --- a/app/(main)/_layout.tsx +++ b/app/(main)/_layout.tsx @@ -1,13 +1,44 @@ /** ========= TABS NAVIGATION ========= */ import { Stack, Tabs } from 'expo-router'; import React from 'react'; +import { BlurView } from 'expo-blur'; +import { StyleSheet } from 'react-native'; +import { Icon, useTheme } from 'react-native-paper'; export default function Tabs_Layout() { + const colors = useTheme() + + const mode = colors.mode return ( - - + ( + // + // ), + }} + > + , + }} + /> - + + ); } diff --git a/app/(modals)/Settings.tsx b/app/(modals)/Settings.tsx new file mode 100644 index 0000000..80d1a28 --- /dev/null +++ b/app/(modals)/Settings.tsx @@ -0,0 +1,5 @@ +import Settings from "@/boards/Settings"; + +export default function Settings_Route() { + return +} diff --git a/app/index.tsx b/app/index.tsx index 6e1ee7a..d0b37c1 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -1,12 +1,12 @@ import Logo from '@/widgets/Logo' import { View } from 'react-native' -import { Text } from 'react-native-paper' +import { FacebookLoader, InstagramLoader } from 'react-native-easy-content-loader'; export default function Splash() { return ( - - {/* */} - Splash + + + {/* */} - ) + ); } \ No newline at end of file diff --git a/app/setup.tsx b/app/setup.tsx index 01968ac..820ab8c 100644 --- a/app/setup.tsx +++ b/app/setup.tsx @@ -17,8 +17,9 @@ export default function Setup(): React.JSX.Element { - {/* === Introduce Screens === */} + {/* === Modals Screens === */} + ); } diff --git a/boards/ExampleAnimated.tsx b/boards/ExampleAnimated.tsx new file mode 100644 index 0000000..98d355b --- /dev/null +++ b/boards/ExampleAnimated.tsx @@ -0,0 +1,377 @@ +/* +Inspiration: https://dribbble.com/shots/3894781-Urbanears-Headphones +Twitter: http://twitter.com/mironcatalin +GitHub: http://github.com/catalinmiron +Video Tutorial: https://youtu.be/cGTD4yYgEHc +Link to example: https://github.com/catalinmiron/react-native-headphones-carousel +*/ + +import React from 'react'; +import { + StyleSheet, + Text, + View, + Image, + Dimensions, + Animated, + ImageRequireSource, +} from 'react-native'; +import type { PagerViewOnPageScrollEventData } from 'react-native-pager-view'; +import PagerView from 'react-native-pager-view'; + +const data = [ + { + type: 'Humlan P', + imageUri: require('../xSetup/assets/example/urbanears_blue.png'), + heading: 'Vibrant colors', + description: 'Four on-trend colorways to seamlessly suit your style.', + key: 'first', + color: '#9dcdfa', + }, + { + type: 'Pampas', + imageUri: require('../xSetup/assets/example/urbanears_pink.png'), + heading: 'Redefined sound', + description: 'A bold statement tuned to perfection.', + key: 'second', + color: '#db9efa', + }, + { + type: 'Humlan P', + imageUri: require('../xSetup/assets/example/urbanears_grey.png'), + heading: 'Great quality', + description: + 'An Urbanears classic! Listen-all-day fit. Striking the perfect balance of effortless technology', + key: 'third', + color: '#999', + }, + { + type: 'Humlan B', + imageUri: require('../xSetup/assets/example/urbanears_mint.png'), + heading: 'From Sweden', + description: 'The “Plattan” in Plattan headphones is Swedish for “the slab.”', + key: 'fourth', + color: '#a1e3a1', + }, +]; +const { width, height } = Dimensions.get('window'); +const LOGO_WIDTH = 220; +const LOGO_HEIGHT = 40; +const DOT_SIZE = 40; +const TICKER_HEIGHT = 40; +const CIRCLE_SIZE = width * 0.6; + +const Circle = ({ scrollOffsetAnimatedValue }: { scrollOffsetAnimatedValue: Animated.Value }) => { + return ( + + {data.map(({ color }, index) => { + const inputRange = [0, 0.5, 0.99]; + const inputRangeOpacity = [0, 0.5, 0.99]; + const scale = scrollOffsetAnimatedValue.interpolate({ + inputRange, + outputRange: [1, 0, 1], + extrapolate: 'clamp', + }); + + const opacity = scrollOffsetAnimatedValue.interpolate({ + inputRange: inputRangeOpacity, + outputRange: [0.2, 0, 0.2], + }); + + return ( + + ); + })} + + ); +}; + +const Ticker = ({ + scrollOffsetAnimatedValue, + positionAnimatedValue, +}: { + scrollOffsetAnimatedValue: Animated.Value; + positionAnimatedValue: Animated.Value; +}) => { + const inputRange = [0, data.length]; + const translateY = Animated.add(scrollOffsetAnimatedValue, positionAnimatedValue).interpolate({ + inputRange, + outputRange: [0, data.length * -TICKER_HEIGHT], + }); + return ( + + + {data.map(({ type }, index) => { + return ( + + {type} + + ); + })} + + + ); +}; + +const Item = ({ + imageUri, + heading, + description, + scrollOffsetAnimatedValue, +}: { + imageUri: ImageRequireSource; + description: string; + heading: string; + scrollOffsetAnimatedValue: Animated.Value; + positionAnimatedValue: Animated.Value; +}) => { + const inputRange = [0, 0.5, 0.99]; + const inputRangeOpacity = [0, 0.5, 0.99]; + const scale = scrollOffsetAnimatedValue.interpolate({ + inputRange, + outputRange: [1, 0, 1], + }); + + const opacity = scrollOffsetAnimatedValue.interpolate({ + inputRange: inputRangeOpacity, + outputRange: [1, 0, 1], + }); + + return ( + + + + + {heading} + + + {description} + + + + ); +}; + +const Pagination = ({ + scrollOffsetAnimatedValue, + positionAnimatedValue, +}: { + scrollOffsetAnimatedValue: Animated.Value; + positionAnimatedValue: Animated.Value; +}) => { + const inputRange = [0, data.length]; + const translateX = Animated.add(scrollOffsetAnimatedValue, positionAnimatedValue).interpolate({ + inputRange, + outputRange: [0, data.length * DOT_SIZE], + }); + + return ( + + + {data.map((item) => { + return ( + + + + ); + })} + + ); +}; + +const AnimatedPagerView = Animated.createAnimatedComponent(PagerView); + +export default function HeadphonesCarouselExample() { + const scrollOffsetAnimatedValue = React.useRef(new Animated.Value(0)).current; + const positionAnimatedValue = React.useRef(new Animated.Value(0)).current; + + return ( + + + ( + [ + { + nativeEvent: { + offset: scrollOffsetAnimatedValue, + position: positionAnimatedValue, + }, + }, + ], + { + listener: ({ nativeEvent: { offset, position } }) => { + console.log(`Position: ${position} Offset: ${offset}`); + }, + useNativeDriver: true, + } + )} + > + {data.map((item, index) => ( + + + + ))} + + + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + itemStyle: { + width, + height, + alignItems: 'center', + justifyContent: 'center', + }, + imageStyle: { + width: width * 0.75, + height: width * 0.75, + resizeMode: 'contain', + flex: 1, + }, + textContainer: { + alignItems: 'flex-start', + alignSelf: 'flex-end', + flex: 0.5, + }, + heading: { + color: '#444', + textTransform: 'uppercase', + fontSize: 24, + fontWeight: '800', + letterSpacing: 2, + marginBottom: 5, + }, + description: { + color: '#ccc', + fontWeight: '600', + textAlign: 'left', + width: width * 0.75, + marginRight: 10, + fontSize: 16, + lineHeight: 16 * 1.5, + }, + logo: { + opacity: 0.9, + height: LOGO_HEIGHT, + width: LOGO_WIDTH, + resizeMode: 'contain', + position: 'absolute', + left: 10, + bottom: 10, + transform: [ + { translateX: -LOGO_WIDTH / 2 }, + { translateY: -LOGO_HEIGHT / 2 }, + { rotateZ: '-90deg' }, + { translateX: LOGO_WIDTH / 2 }, + { translateY: LOGO_HEIGHT / 2 }, + ], + }, + pagination: { + position: 'absolute', + right: 20, + bottom: 40, + flexDirection: 'row', + height: DOT_SIZE, + }, + paginationDot: { + width: DOT_SIZE * 0.3, + height: DOT_SIZE * 0.3, + borderRadius: DOT_SIZE * 0.15, + }, + paginationDotContainer: { + width: DOT_SIZE, + alignItems: 'center', + justifyContent: 'center', + }, + paginationIndicator: { + width: DOT_SIZE, + height: DOT_SIZE, + borderRadius: DOT_SIZE / 2, + borderWidth: 2, + borderColor: '#ddd', + }, + tickerContainer: { + position: 'absolute', + top: 40, + left: 20, + overflow: 'hidden', + height: TICKER_HEIGHT, + }, + tickerText: { + fontSize: TICKER_HEIGHT, + lineHeight: TICKER_HEIGHT, + textTransform: 'uppercase', + fontWeight: '800', + }, + + circleContainer: { + alignItems: 'center', + justifyContent: 'center', + }, + circle: { + width: CIRCLE_SIZE, + height: CIRCLE_SIZE, + borderRadius: CIRCLE_SIZE / 2, + position: 'absolute', + top: '15%', + }, +}); diff --git a/boards/ExampleTiktok.tsx b/boards/ExampleTiktok.tsx new file mode 100644 index 0000000..f1e5433 --- /dev/null +++ b/boards/ExampleTiktok.tsx @@ -0,0 +1,34 @@ +import { StyleSheet, View } from 'react-native'; +import PagerView from 'react-native-pager-view'; +import { Text, useTheme } from 'react-native-paper'; + +export default function ExampleTiktok() { + const colors = useTheme() + + return ( + + + + First page + Swipe ➡️ + + + Second page + + + Third page + + + + ); +} + +const styles = StyleSheet.create({ + viewPager: { + flex: 1, + }, + page: { + justifyContent: 'center', + alignItems: 'center', + }, +}); diff --git a/boards/Home.tsx b/boards/Home.tsx new file mode 100644 index 0000000..cf679d2 --- /dev/null +++ b/boards/Home.tsx @@ -0,0 +1,30 @@ +import { router } from 'expo-router'; + +import Appbar from '@/widgets/Appbar'; +import Main from '@/widgets/Main'; +import { StyleSheet, View } from 'react-native'; +import PagerView from 'react-native-pager-view'; +import { Text } from 'react-native-paper'; + +export default function Home() { + const routeToSettings = () => router.push('/Settings'); + + return ( + <> + +
+ +
+ + ); +} + +const styles = StyleSheet.create({ + viewPager: { + flex: 1, + }, + page: { + justifyContent: 'center', + alignItems: 'center', + }, +}); diff --git a/boards/Login.tsx b/boards/Login.tsx index 5a4ed5c..b9555f2 100644 --- a/boards/Login.tsx +++ b/boards/Login.tsx @@ -51,7 +51,7 @@ export default function Login(): React.JSX.Element { const toggleSecureText = () => setSecureText(!secureText); return ( - +
Login.
diff --git a/boards/Oboarding.tsx b/boards/Oboarding.tsx index df1aac0..b0904bb 100644 --- a/boards/Oboarding.tsx +++ b/boards/Oboarding.tsx @@ -1,20 +1,20 @@ -import React, { useContext, useEffect, useRef, useState } from 'react'; -import { Dimensions, FlatList, StyleSheet, View } from 'react-native'; import { onboardBones, onboardBonesAR } from '@constants/onboard_setup'; +import React, { useContext, useEffect, useRef, useState } from 'react'; +import { Dimensions, FlatList, StyleSheet, TouchableOpacity, View } from 'react-native'; import OnboardingButton from '../widgets/OnboardingButton'; +import LOCALIZATION from '@/xSetup/context/locales'; +import { router } from 'expo-router'; +import { useTheme } from 'react-native-paper'; import { SafeAreaView } from 'react-native-safe-area-context'; -import OnboardSlider from '../widgets/OnboardSlider'; -import SliderIndicator from '../widgets/SliderIndicator'; import { useNavigationStore } from '../stores/useNavigationStore'; import { useRemoteStore } from '../stores/useRemoteStore'; -import LOCALIZATION from '@/xSetup/context/locales'; -import { useTheme } from 'react-native-paper'; -import { router } from 'expo-router'; +import OnboardSlider from '../widgets/OnboardSlider'; +import SliderIndicator from '../widgets/SliderIndicator'; export default function Onboarding () { const colors = useTheme(); - const l = useContext(LOCALIZATION) + const l = useContext(LOCALIZATION); const { shared } = useRemoteStore(); const setSeenOnboard = useNavigationStore((state) => state.setSeenOnboard); const [currentSlideIndex, setCurrentSlideIndex] = useState(0); @@ -37,13 +37,13 @@ export default function Onboarding () { useEffect(() => { if (SKIP) { - console.log('SKIP') + console.log('SKIP'); setSeenOnboard(true); setLoading(true); - router.replace('/Welcome') + router.replace('/Welcome'); } - }, [SKIP]) - + }, [SKIP]); + const handleOnPress = () => { if (currentSlideIndex == data?.length - 1) { setSeenOnboard(true); @@ -66,6 +66,13 @@ export default function Onboarding () { setCurrentSlideIndex(nextSlideIndex); }; + // Function to navigate to a specific card + const navigateToCard = (index) => { + const nextSlideOffset = index * width; + slidesRef?.current?.scrollToOffset({ offset: nextSlideOffset }); + setCurrentSlideIndex(index); + }; + const RENDEROnboardSlider = ({ item }) => ; return ( @@ -84,14 +91,12 @@ export default function Onboarding () {
{data?.map((_, index) => ( + navigateToCard(index)}> + ))} - + ); }; diff --git a/boards/Register.tsx b/boards/Register.tsx index cf27c31..fe94853 100644 --- a/boards/Register.tsx +++ b/boards/Register.tsx @@ -46,7 +46,7 @@ export default function Register() { const toggleSecureText = () => setSecureText(!secureText); return ( - + Register diff --git a/boards/Reset.tsx b/boards/Reset.tsx new file mode 100644 index 0000000..3ee5564 --- /dev/null +++ b/boards/Reset.tsx @@ -0,0 +1,70 @@ +import Background from '@widgets/Background'; +import ActionButton from '@widgets/Button'; +import Header from '@widgets/Header'; +import Logo from '@widgets/Logo'; +import React, { useState } from 'react'; +import { HelperText, Paragraph, TextInput } from 'react-native-paper'; +// import TextInput from '@widgets/TextInput'; +import BackButton from '@widgets/BackButton'; + +import { validateEmail } from '@validations/validateEmail'; + +import executeAuth from '@/events/executeAuth'; +import Snackbar from '@/widgets/Snackbar'; + +export default function Reset(): React.JSX.Element { + const [email, setEmail] = useState({ value: '', error: '' }); + const [loading, setLoading] = useState(false); + + const [error, setError] = useState(''); + + const { executeResetPassword } = executeAuth(); + + const onResetPassword = async () => { + console.log('VALIDATE') + const emailError = validateEmail(email.value); + console.log('EMAIL ERROR', emailError) + setLoading(true); + if (emailError) { + setEmail({ ...email, error: emailError }); + setLoading(false); + return; + } + try { + await executeResetPassword(email.value); + } catch (error: any) { + console.log('ERROR:', error); + setLoading(false); + setError(error); + } + }; + + return ( + + + +
Reset your password.
+ setEmail({ value: text, error: '' })} + error={!!email.error} + autoCapitalize='none' + autoComplete='email' + textContentType='emailAddress' + keyboardType='email-address' + style={{ width: '100%' }} + /> + + {email.error} + + + {loading ? 'Sending ..' : 'Continue'} + + You will receive an email with the reset link. + 0} autoDismiss snackbarText={error} /> +
+ ); +} \ No newline at end of file diff --git a/boards/Settings.tsx b/boards/Settings.tsx new file mode 100644 index 0000000..99bf046 --- /dev/null +++ b/boards/Settings.tsx @@ -0,0 +1,70 @@ +import executeAuth from '@/events/executeAuth'; +import { useUserStore } from '@/stores/useUserStore'; +import Background from '@/widgets/Background'; +import Logo from '@/widgets/Logo'; +import { View } from '@/xSetup/ui'; +import React, { useState } from 'react'; +import { StyleSheet, useColorScheme } from 'react-native'; +import { List, SegmentedButtons, useTheme } from 'react-native-paper'; + +export default function Settings() { + const [expanded, setExpanded] = useState(true); + const handlePress = () => setExpanded(!expanded); + const colors = useTheme() + + const [error, setError] = useState(''); + + const { executeLogout } = executeAuth(); + + const logout = async () => { + try { + await executeLogout(); + } catch (error: any) { + setError(error.message); + } + }; + + return ( + + + + + Some title + } + /> + } /> + + + ); +} + +function DarkMode() { + const { dark, setDark } = useUserStore(); + const getDeviceAppearance = useColorScheme(); // 'light' or 'dark' + + const userSettingsDark = dark != null ? (dark ? 'dark' : 'light') : 'light'; + const [value, setValue] = useState(dark != null ? userSettingsDark : getDeviceAppearance); + const colors = useTheme(); + + return ( + { + const isDark = v === 'dark' ? true : false + setDark(isDark) + setValue(v) + }} + buttons={[ + { + value: 'dark', + label: '', + icon: 'moon-waning-crescent', + }, + { value: 'light', label: '', icon: 'white-balance-sunny' }, + ]} + /> + ); +} diff --git a/events/executeAuth.ts b/events/executeAuth.ts index 304b89f..9eb69d5 100644 --- a/events/executeAuth.ts +++ b/events/executeAuth.ts @@ -174,8 +174,28 @@ export default function executeAuth() { const executeResetPassword = async (email: string): Promise => { try { await sendPasswordResetEmail(auth, email); - } catch (err) { - throw err; + router.push('/Login'); + } catch (error: any) { + switch (error.code) { + case 'auth/email-already-in-use': + // vexoit('AUTH', { method: 'signup', status: 'failed', event: 'email-already-in-use' }); + throw l.error_email_in_use; + case 'auth/wrong-password': + // vexoit('AUTH', { method: 'login', status: 'failed', event: 'auth/wrong-password' }); + throw l.error_password_wrong; + case 'auth/too-many-requests': + // vexoit('AUTH', { method: 'signup', status: 'failed', event: 'too-many-requests' }); + throw l.error_account_locked; + case 'auth/invalid-email': + // vexoit('AUTH', { method: 'login', status: 'failed', event: 'invalid-email' }); + throw l.error_email_invalid; + case 'auth/weak-password': + // vexoit('AUTH', { method: 'signup', status: 'failed', event: 'weak-password' }); + throw l.error_password_too_weak; + default: + // vexoit('AUTH', { method: 'signup', status: 'failed', event: 'error' }); + throw l.error_occurred; + } } }; diff --git a/package.json b/package.json index 8ec1741..d607716 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@react-navigation/drawer": "^6.6.6", "@react-navigation/material-top-tabs": "^6.6.5", "@react-navigation/native": "^6.1.9", + "@shopify/flash-list": "1.4.3", "@shopify/react-native-skia": "0.1.196", "@tanstack/react-query": "^5.0.0", "@th3rdwave/react-navigation-bottom-sheet": "^0.2.7", @@ -69,6 +70,7 @@ "react-dom": "18.2.0", "react-native": "0.72.6", "react-native-circular-progress-indicator": "^4.4.2", + "react-native-easy-content-loader": "^0.3.2", "react-native-gesture-handler": "~2.12.0", "react-native-maps": "1.7.1", "react-native-pager-view": "6.2.0", diff --git a/packages.md b/packages.md index 012e354..258cc52 100644 --- a/packages.md +++ b/packages.md @@ -1,6 +1,6 @@ # Expo Project -- npx expo install axios zustand moment react-native-paper react-native-tab-view @tanstack/react-query @gorhom/bottom-sheet@^4 google-libphonenumber react-native-webview react-native-circular-progress-indicator throttle-debounce geofire victory-native react-native-qrcode-svg reanimated-color-picker expo-screen-orientation @react-native-async-storage/async-storage @react-native-masked-view/masked-view react-native-pager-view firebase expo-file-system expo-image-picker expo-random expo-updates expo-localization expo-device expo-location expo-task-manager react-native-maps expo-notifications expo-permissions expo-linear-gradient expo-barcode-scanner expo-constants react-native-svg react-native-reanimated expo-sms expo-sharing expo-clipboard expo-blur expo-store-review expo-linking expo-av expo-system-ui react-native-purchases expo-dev-client expo-build-properties vexo-analytics expo-tracking-transparency @shopify/react-native-skia @react-navigation/native expo-image @react-navigation/material-top-tabs @react-navigation/drawer react-native-safe-area-context @react-native-community/datetimepicker @th3rdwave/react-navigation-bottom-sheet +- npx expo install axios zustand moment react-native-paper react-native-tab-view @tanstack/react-query @gorhom/bottom-sheet@^4 google-libphonenumber react-native-webview react-native-circular-progress-indicator throttle-debounce geofire victory-native react-native-qrcode-svg reanimated-color-picker expo-screen-orientation @react-native-async-storage/async-storage @react-native-masked-view/masked-view react-native-pager-view firebase expo-file-system expo-image-picker expo-random expo-updates expo-localization expo-device expo-location expo-task-manager react-native-maps expo-notifications expo-permissions expo-linear-gradient expo-barcode-scanner expo-constants react-native-svg react-native-reanimated expo-sms expo-sharing expo-clipboard expo-blur expo-store-review expo-linking expo-av expo-system-ui react-native-purchases expo-dev-client expo-build-properties vexo-analytics expo-tracking-transparency @shopify/react-native-skia @react-navigation/native expo-image @react-navigation/material-top-tabs @react-navigation/drawer react-native-safe-area-context @react-native-community/datetimepicker bottoms @shopify/flash-list react-native-easy-content-loader - npx expo install --fix @@ -32,10 +32,13 @@ - giftedchat - react-native-calendar - bouncy checkbox react-native-bouncy-checkbox -- Skelton react-content-loader - Pager react-native-pager-view - Flashlist +- npx expo install bottoms +- npx expo install react-native-easy-content-loader +- npx expo install @shopify/flash-list +- npx expo install react-native-pager-view - npx expo install expo-image - npx expo install expo-screen-orientation - npx expo install @react-native-async-storage/async-storage diff --git a/widgets/Appbar.tsx b/widgets/Appbar.tsx index 5686bad..45fd172 100644 --- a/widgets/Appbar.tsx +++ b/widgets/Appbar.tsx @@ -2,15 +2,27 @@ import { Appbar as PaperAppbar, useTheme } from 'react-native-paper'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import React from 'react'; +interface Action { + icon: string; + onPress: () => void; +} + +interface AppbarProps { + title?: string; + showBackAction?: boolean; + onBackActionPress?: () => void; + actions?: Action[]; +} + export default function Appbar({ title = 'Title', showBackAction = false, onBackActionPress = () => {}, actions = [], -}) { +}: AppbarProps) { const insets = useSafeAreaInsets(); const colors = useTheme(); - + return ( {showBackAction && } diff --git a/widgets/Background.tsx b/widgets/Background.tsx index 52b6ae4..b5302d5 100644 --- a/widgets/Background.tsx +++ b/widgets/Background.tsx @@ -1,35 +1,78 @@ import React, { ReactNode } from 'react'; -import { ImageBackground, KeyboardAvoidingView } from 'react-native'; +import { ImageBackground, KeyboardAvoidingView, StyleProp, View, ViewStyle } from 'react-native'; import { useTheme } from 'react-native-paper'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; -export default function Background({ children }: { children: ReactNode }): React.JSX.Element { +interface MainProps { + children?: ReactNode; + center?: 'center' | 'top' | 'left' | 'right' | 'bottom'; + padding?: number; + safe?: 'none' | 'all' | 'top' | 'bottom' | 'left' | 'right'; + color?: string; + keyboard?: boolean; +} - const colors = useTheme() +export default function Background({ + children, + center = 'center', + padding = 20, + safe = 'none', + color, + keyboard = false, +}: MainProps): React.JSX.Element { + const colors = useTheme(); + const { top, bottom, left, right } = useSafeAreaInsets(); + const background = color ? color : colors.colors.background; - return ( - - - {children} - - - ); -} \ No newline at end of file + const mainStyles: StyleProp = { + flex: 1, + padding, + width: '100%', + alignSelf: 'center', + backgroundColor: background, + }; + + if (safe === 'all') { + mainStyles.paddingTop = top + padding; + mainStyles.paddingBottom = bottom + padding; + mainStyles.paddingLeft = left + padding; + mainStyles.paddingRight = right + padding; + } else if (safe === 'top') { + mainStyles.paddingTop = top; + } else if (safe === 'bottom') { + mainStyles.paddingBottom = bottom; + } else if (safe === 'left') { + mainStyles.paddingLeft = left; + } else if (safe === 'right') { + mainStyles.paddingRight = right; + } + + if (center === 'center') { + mainStyles.justifyContent = 'center'; + mainStyles.alignItems = 'center'; + } else if (center === 'top') { + mainStyles.justifyContent = 'flex-start'; + mainStyles.alignItems = 'center'; + } else if (center === 'left') { + mainStyles.justifyContent = 'flex-start'; + mainStyles.alignItems = 'flex-start'; + } else if (center === 'right') { + mainStyles.justifyContent = 'flex-end'; + mainStyles.alignItems = 'flex-end'; + } else if (center === 'bottom') { + mainStyles.justifyContent = 'flex-end'; + mainStyles.alignItems = 'center'; + } + + return ( + + {keyboard ? ( + + {children} + + ) : ( + {children} + )} + + ); +} diff --git a/widgets/Main.tsx b/widgets/Main.tsx new file mode 100644 index 0000000..725cc76 --- /dev/null +++ b/widgets/Main.tsx @@ -0,0 +1,66 @@ +import React, { ReactNode } from 'react'; +import { StyleProp, View, ViewStyle } from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import { useTheme } from 'react-native-paper'; + +interface MainProps { + children?: ReactNode; + center?: 'center' | 'top' | 'left' | 'right' | 'bottom'; + padding?: number; + safe?: 'none' | 'all' | 'top' | 'bottom' | 'left' | 'right'; + color?: string +} + +export default function Main({ + children, + center = 'center', + padding = 0, + safe = 'none', + color +}: MainProps): React.JSX.Element { + const colors = useTheme(); + const { top, bottom, left, right } = useSafeAreaInsets(); + const background = color ? color : colors.colors.background + + const mainStyles: StyleProp = { + flex: 1, + width:'100%', + padding, + alignSelf: 'center', + backgroundColor: background, + }; + + if (safe === 'all') { + mainStyles.paddingTop = top + padding; + mainStyles.paddingBottom = bottom + padding; + mainStyles.paddingLeft = left + padding; + mainStyles.paddingRight = right + padding; + } else if (safe === 'top') { + mainStyles.paddingTop = top; + } else if (safe === 'bottom') { + mainStyles.paddingBottom = bottom; + } else if (safe === 'left') { + mainStyles.paddingLeft = left; + } else if (safe === 'right') { + mainStyles.paddingRight = right; + } + + if (center === 'center') { + mainStyles.justifyContent = 'center'; + mainStyles.alignItems = 'center'; + } else if (center === 'top') { + mainStyles.justifyContent = 'flex-start'; + mainStyles.alignItems = 'center'; + } else if (center === 'left') { + mainStyles.justifyContent = 'flex-start'; + mainStyles.alignItems = 'flex-start'; + } else if (center === 'right') { + mainStyles.justifyContent = 'flex-end'; + mainStyles.alignItems = 'flex-end'; + } else if (center === 'bottom') { + mainStyles.justifyContent = 'flex-end'; + mainStyles.alignItems = 'center'; + } + + return {children}; +} diff --git a/widgets/OnboardingButton.tsx b/widgets/OnboardingButton.tsx index 5fd5dfa..dfb9ae5 100644 --- a/widgets/OnboardingButton.tsx +++ b/widgets/OnboardingButton.tsx @@ -44,7 +44,7 @@ export default function OnboardingButton({ loading, handleOnPress, lastSlide }) }, ]} > - {buttonText} + {buttonText} ); }; diff --git a/xSetup/assets/example/ue_black_logo.png b/xSetup/assets/example/ue_black_logo.png new file mode 100644 index 0000000..b61e283 Binary files /dev/null and b/xSetup/assets/example/ue_black_logo.png differ diff --git a/xSetup/assets/example/urbanears_blue.png b/xSetup/assets/example/urbanears_blue.png new file mode 100644 index 0000000..c6b0413 Binary files /dev/null and b/xSetup/assets/example/urbanears_blue.png differ diff --git a/xSetup/assets/example/urbanears_grey.png b/xSetup/assets/example/urbanears_grey.png new file mode 100644 index 0000000..f3449a1 Binary files /dev/null and b/xSetup/assets/example/urbanears_grey.png differ diff --git a/xSetup/assets/example/urbanears_mint.png b/xSetup/assets/example/urbanears_mint.png new file mode 100644 index 0000000..57ba35b Binary files /dev/null and b/xSetup/assets/example/urbanears_mint.png differ diff --git a/xSetup/assets/example/urbanears_pink.png b/xSetup/assets/example/urbanears_pink.png new file mode 100644 index 0000000..3cdc088 Binary files /dev/null and b/xSetup/assets/example/urbanears_pink.png differ diff --git a/xSetup/assets/images/logo.png b/xSetup/assets/images/logo.png index 7295e55..b23fa76 100644 Binary files a/xSetup/assets/images/logo.png and b/xSetup/assets/images/logo.png differ diff --git a/xSetup/assets/images/logox.png b/xSetup/assets/images/logox.png deleted file mode 100644 index b23fa76..0000000 Binary files a/xSetup/assets/images/logox.png and /dev/null differ diff --git a/xSetup/assets/images/logoxx.png b/xSetup/assets/images/logoxx.png new file mode 100644 index 0000000..7295e55 Binary files /dev/null and b/xSetup/assets/images/logoxx.png differ diff --git a/yarn.lock b/yarn.lock index aefc6c0..dffccf6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2871,6 +2871,14 @@ component-type "^1.2.1" join-component "^1.1.0" +"@shopify/flash-list@1.4.3": + version "1.4.3" + resolved "https://registry.yarnpkg.com/@shopify/flash-list/-/flash-list-1.4.3.tgz#b7a4fe03d64f3c5ce9646859b49b9d95307f203d" + integrity sha512-jtIReAbwWzYBV0dQ6Io9wBX+pD0C4qQFMrb5/fkEvX8PYDgBl5KRYvpfr9WLLj8CV2Jsn1X0mYOsB+ysWrI/8g== + dependencies: + recyclerlistview "4.2.0" + tslib "2.4.0" + "@shopify/react-native-skia@0.1.196": version "0.1.196" resolved "https://registry.npmjs.org/@shopify/react-native-skia/-/react-native-skia-0.1.196.tgz" @@ -5592,6 +5600,11 @@ hermes-profile-transformer@^0.0.6: dependencies: source-map "^0.7.3" +hex-to-rgba@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/hex-to-rgba/-/hex-to-rgba-2.0.1.tgz#4176977882a1cb32b83ce5ab1db6828ab84d5a13" + integrity sha512-5XqPJBpsEUMsseJUi2w2Hl7cHFFi3+OO10M2pzAvKB1zL6fc+koGMhmBqoDOCB4GemiRM/zvDMRIhVw6EkB8dQ== + hoist-non-react-statics@^3.3.0: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" @@ -6753,7 +6766,7 @@ lodash.camelcase@^4.3.0: resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== -lodash.debounce@^4.0.8: +lodash.debounce@4.0.8, lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== @@ -7900,7 +7913,7 @@ prompts@^2.0.1, prompts@^2.2.1, prompts@^2.3.2, prompts@^2.4.0: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@*, prop-types@^15.7.2, prop-types@^15.8.0: +prop-types@*, prop-types@15.8.1, prop-types@^15.7.2, prop-types@^15.8.0: version "15.8.1" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -8127,6 +8140,13 @@ react-native-circular-progress-indicator@^4.4.2: dependencies: react-native-redash "*" +react-native-easy-content-loader@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/react-native-easy-content-loader/-/react-native-easy-content-loader-0.3.2.tgz#5c0dcd69c84c5370365153162b21fe82098459c3" + integrity sha512-gLlfEVjOgflWKWoB255GFMgvIkSv5ScVbCvkCGj6KDelFenqMuePnW3yqDvkSGl1xAds76NpqO+JgOuYq7gXMw== + dependencies: + hex-to-rgba "^2.0.1" + react-native-gesture-handler@~2.12.0: version "2.12.1" resolved "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.12.1.tgz" @@ -8376,6 +8396,15 @@ recast@^0.21.0: source-map "~0.6.1" tslib "^2.0.1" +recyclerlistview@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/recyclerlistview/-/recyclerlistview-4.2.0.tgz#a140149aaa470c9787a1426452651934240d69ef" + integrity sha512-uuBCi0c+ggqHKwrzPX4Z/mJOzsBbjZEAwGGmlwpD/sD7raXixdAbdJ6BTcAmuWG50Cg4ru9p12M94Njwhr/27A== + dependencies: + lodash.debounce "4.0.8" + prop-types "15.8.1" + ts-object-utils "0.0.5" + redent@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz" @@ -9285,6 +9314,16 @@ ts-interface-checker@^0.1.9: resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz" integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== +ts-object-utils@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/ts-object-utils/-/ts-object-utils-0.0.5.tgz#95361cdecd7e52167cfc5e634c76345e90a26077" + integrity sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA== + +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0: version "2.6.2" resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz"