diff --git a/app.d.ts b/app.d.ts new file mode 100644 index 0000000..a13e313 --- /dev/null +++ b/app.d.ts @@ -0,0 +1 @@ +/// diff --git a/app.json b/app.json index 74e390d..986ec70 100644 --- a/app.json +++ b/app.json @@ -42,7 +42,7 @@ ] ], "experiments": { - "typedRoutes": false + "typedRoutes": true }, "extra": { "router": { diff --git a/app/(tabs)/[id].tsx b/app/(tabs)/[id].tsx index 73d73ba..79778a5 100644 --- a/app/(tabs)/[id].tsx +++ b/app/(tabs)/[id].tsx @@ -13,6 +13,7 @@ const NewPage = () => { Hang on, This feature is in development Process + ); }; diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 9bafd2c..f97dba5 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -1,14 +1,24 @@ import { Link } from "expo-router"; -import React from "react"; +import React, { useEffect } from "react"; import { Text, ScrollView, TouchableOpacity, StyleSheet } from "react-native"; +import { storage } from "@/utils/mmkvHelpers"; + //TODO: this is homepage of the app //TODO: add a notification icon //TODO: it will have details of the society, details of the resident, details of the flat, details of the family members, details of the parking, details of the utilities, details of the maintenance, details of the bills, details of the orders, details of the payments, details of the receipts, details of the complaints, details of the suggestions, details of the feedbacks, details of the polls, details of the announcements, details of the notices, details of the chats, details of the events, details of the posts, details of the category, details of the community, details of the account, details of the index //TODO: options of payment dues, gate updates, guest notification, help, etc //TODO: in notification component it will push notifications of payment dues, gate updates, guest notification, help, etc -const index = () => { +export const Index = () => { + useEffect(() => { + // storage.clearAll(); + const keys = storage.getAllKeys(); + //fetch keys as per chatcard id + if (!keys.length) { + } + }); + return ( @@ -86,5 +96,3 @@ const styles = StyleSheet.create({ fontWeight: "bold", }, }); - -export default index; diff --git a/app/onboarding/index.tsx b/app/onboarding/index.tsx new file mode 100644 index 0000000..ce6026f --- /dev/null +++ b/app/onboarding/index.tsx @@ -0,0 +1,141 @@ +/* eslint-disable prettier/prettier */ +import { AntDesign } from "@expo/vector-icons"; +import Entypo from "@expo/vector-icons/Entypo"; +import * as Font from "expo-font"; +import { router } from "expo-router"; +import * as SplashScreen from "expo-splash-screen"; +import React, { useCallback, useEffect } from "react"; +import { View } from "react-native"; +import Animated, { + useAnimatedRef, + useAnimatedScrollHandler, + useDerivedValue, + useSharedValue, +} from "react-native-reanimated"; + +import OnboardingPage, { width } from "@/components/OnboardingPage"; +import PaginationDot from "@/components/PaginationDot"; +import { PAGES, ONBOARD_BG } from "@/constants/onboarding"; +import { IS_ONBOARDED_KEY } from "@/utils/costants/chat"; +import { storage } from "@/utils/mmkvHelpers"; + +SplashScreen.preventAutoHideAsync(); + +export default function OnboardingScreen() { + const translateX = useSharedValue(0); + + const scrollHandler = useAnimatedScrollHandler({ + onScroll: (event) => { + translateX.value = event.contentOffset.x; + }, + }); + + const activeIndex = useDerivedValue(() => { + return Math.round(translateX.value / width); + }); + + const scrollRef = useAnimatedRef(); + const onIconPress = useCallback(async () => { + if (scrollRef.current) { + const nextIndex = activeIndex.value + 1; + if (nextIndex < PAGES.length) { + scrollRef.current.scrollTo({ + x: nextIndex * width, + animated: true, + }); + } else { + // Store the onboarding status in AsyncStorage + storage.set(IS_ONBOARDED_KEY, true); + router.replace("/(tabs)/home"); + } + } + }, [activeIndex]); + + console.log("onboarding rendered"); + + const [appIsReady, setAppIsReady] = React.useState(false); + + useEffect(() => { + async function prepare() { + try { + await Font.loadAsync(Entypo.font); + + await new Promise((resolve) => setTimeout(resolve)); + } catch (e) { + console.warn(e); + } finally { + setAppIsReady(true); + } + } + + prepare(); + }, []); + + const onLayoutRootView = useCallback(async () => { + if (appIsReady) { + await SplashScreen.hideAsync(); + } + }, [appIsReady]); + + if (!appIsReady) { + return null; + } + + return ( + + + {PAGES.map((page, index) => ( + + ))} + + + {/* FOOTER */} + + + {/* Paginator */} + + + {PAGES.map((_, index) => { + return ( + + ); + })} + + + {/* Icon or Button Container */} + + + + + + + ); +} diff --git a/assets/images/clinic-1.jpg b/assets/images/clinic-1.jpg new file mode 100644 index 0000000..085f93f Binary files /dev/null and b/assets/images/clinic-1.jpg differ diff --git a/assets/images/clinic-2.png b/assets/images/clinic-2.png new file mode 100644 index 0000000..96de4b3 Binary files /dev/null and b/assets/images/clinic-2.png differ diff --git a/assets/images/clinic-3.png b/assets/images/clinic-3.png new file mode 100644 index 0000000..5c9ab0b Binary files /dev/null and b/assets/images/clinic-3.png differ diff --git a/components/OnboardingPage.tsx b/components/OnboardingPage.tsx new file mode 100644 index 0000000..3ea6e79 --- /dev/null +++ b/components/OnboardingPage.tsx @@ -0,0 +1,92 @@ +import React from "react"; +import { Dimensions, View, Text } from "react-native"; +import Animated, { + Extrapolation, + interpolate, + useAnimatedStyle, +} from "react-native-reanimated"; + +import { PageInterface } from "@/constants/onboarding"; + +interface PageProps { + page: PageInterface; + translateX: Animated.SharedValue; + index: number; +} + +const width = Dimensions.get("window").width; +const height = Dimensions.get("window").height; + +const CIRCLE_WIDTH = width * 0.7; + +const OnboardingPage: React.FC = ({ page, translateX, index }) => { + const inputRange = [(index - 1) * width, index * width, (index + 1) * width]; + + const onboardImageStyle = useAnimatedStyle(() => { + const progress = interpolate( + translateX.value, + inputRange, + [0, 0, 1], + Extrapolation.CLAMP, + ); + + const opacity = interpolate( + translateX.value, + inputRange, + [0.5, 1, 0.5], + Extrapolation.CLAMP, + ); + + return { + opacity, + transform: [ + { + rotate: `${progress * Math.PI}rad`, + }, + ], + }; + }); + + return ( + + + {/* Circle */} + + + + + + {page.title} + + + {page.description} + + + ); +}; +export { width, height }; + +export default OnboardingPage; diff --git a/components/PaginationDot.tsx b/components/PaginationDot.tsx new file mode 100644 index 0000000..5929c0e --- /dev/null +++ b/components/PaginationDot.tsx @@ -0,0 +1,33 @@ +import React from "react"; +import Animated, { + useAnimatedStyle, + withTiming, +} from "react-native-reanimated"; + +interface PaginationDotProps { + index: number; + activeDotIndex?: Animated.SharedValue; +} + +const PaginationDot: React.FC = ({ + activeDotIndex, + index, +}) => { + const paginatorStyle = useAnimatedStyle(() => { + const isActive = activeDotIndex?.value === index; + return { + backgroundColor: withTiming(isActive ? "black" : "white", { + duration: 300, + }), + width: 20, + height: 20, + marginHorizontal: 5, + borderRadius: 10, + borderWidth: 1, + }; + }); + + return ; +}; + +export default PaginationDot; diff --git a/constants/onboarding.ts b/constants/onboarding.ts new file mode 100644 index 0000000..c451e44 --- /dev/null +++ b/constants/onboarding.ts @@ -0,0 +1,30 @@ +/* eslint-disable prettier/prettier */ +import { ImageProps } from "react-native"; + +export const ONBOARD_BG = "#F1F1F1"; + +export interface PageInterface extends Pick { + title: string; + description: string; +} + +export const PAGES: PageInterface[] = [ + { + title: "Wellness Guide", + description: + "Discover personalized health advice and lifestyle tips for optimal wellness", + source: require("../assets/images/clinic-1.jpg"), + }, + { + title: "Medication Manager", + description: + "Effortlessly organize and track your medications and dosage guidance.", + source: require("../assets/images/clinic-2.png"), + }, + { + title: "Health Tracker", + description: + "Monitor your vitals, symptoms, and progress on your journey to better health", + source: require("../assets/images/clinic-3.png"), + }, +]; diff --git a/expo-env.d.ts b/expo-env.d.ts new file mode 100644 index 0000000..bf3c169 --- /dev/null +++ b/expo-env.d.ts @@ -0,0 +1,3 @@ +/// + +// NOTE: This file should not be edited and should be in your git ignore diff --git a/tailwind.config.js b/tailwind.config.js index 8b36cdf..fc6b366 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,11 +1,11 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - content: [ - "./App.{js,jsx,ts,tsx}", - ".//**/*.{js,jsx,ts,tsx}", - ], + content: ["./app/**/*.{js,jsx,ts,tsx}", "./components/**/*.{js,jsx,ts,tsx}"], theme: { extend: {}, }, + // future: { + // hoverOnlyWhenSupported: true, + // }, plugins: [], }; diff --git a/tsconfig.json b/tsconfig.json index 09447a2..f47de09 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,6 +12,7 @@ "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts", - "app/PushNotifications.tsx" + "app/PushNotifications.tsx", + "metro.config.ts" ] } diff --git a/utils/mmkvHelpers.ts b/utils/mmkvHelpers.ts index c354b43..b5e2d2c 100644 --- a/utils/mmkvHelpers.ts +++ b/utils/mmkvHelpers.ts @@ -1,5 +1,4 @@ import { MMKV } from "react-native-mmkv"; - export const storage = new MMKV(); const CHAT_PREFIX = "chat:";