├── .gitignore ├── README.md ├── api └── index.ts ├── app.json ├── app ├── (app) │ ├── (tabs) │ │ ├── (home) │ │ │ ├── _layout.tsx │ │ │ ├── detail.tsx │ │ │ └── index.tsx │ │ ├── _layout.tsx │ │ ├── cart.tsx │ │ ├── explore.tsx │ │ └── profile.tsx │ └── _layout.tsx ├── +html.tsx ├── +not-found.tsx ├── _layout.tsx └── login.tsx ├── assets ├── fonts │ └── SpaceMono-Regular.ttf └── images │ ├── adaptive-icon.png │ ├── favicon.png │ ├── icon.png │ ├── partial-react-logo.png │ ├── react-logo.png │ ├── react-logo@2x.png │ ├── react-logo@3x.png │ ├── shop │ ├── adaptive-icon.png │ ├── baby.png │ ├── banner.png │ ├── banner6.png │ ├── c1.png │ ├── c2.png │ ├── c3.png │ ├── cart_empty.json │ ├── css3.png │ ├── icon.png │ ├── kid.png │ ├── man.png │ ├── n.png │ ├── pet.png │ ├── splash.png │ ├── t1.png │ ├── t2.png │ ├── t3.png │ ├── t4.png │ ├── teen.png │ ├── w1.png │ ├── w2.png │ ├── w3.png │ ├── w4.png │ ├── w5.png │ └── woman.png │ └── splash.png ├── babel.config.js ├── components ├── Collapsible.tsx ├── ExternalLink.tsx ├── HelloWave.tsx ├── ParallaxScrollView.tsx ├── ThemedText.tsx ├── ThemedView.tsx ├── __tests__ │ ├── ThemedText-test.tsx │ └── __snapshots__ │ │ └── ThemedText-test.tsx.snap ├── navigation │ └── TabBarIcon.tsx └── shop │ ├── Cart.tsx │ ├── Category.tsx │ ├── Product.tsx │ ├── Title.tsx │ └── ViewPager.tsx ├── config └── index.ts ├── constants └── Colors.ts ├── data ├── db.json ├── index.ts └── shop │ ├── baby.png │ ├── banner.png │ ├── banner6.png │ ├── c1.png │ ├── c2.png │ ├── c3.png │ ├── css3.png │ ├── icon.png │ ├── kid.png │ ├── man.png │ ├── n.png │ ├── pet.png │ ├── splash.png │ ├── t1.png │ ├── t2.png │ ├── t3.png │ ├── t4.png │ ├── teen.png │ ├── w1.png │ ├── w2.png │ ├── w3.png │ ├── w4.png │ ├── w5.png │ └── woman.png ├── hooks ├── useColorScheme.ts ├── useColorScheme.web.ts ├── useRedux.ts ├── useStorageState.ts └── useThemeColor.ts ├── package-lock.json ├── package.json ├── providers ├── ctx.tsx └── redux │ ├── cartSlice.ts │ ├── productSlice.ts │ ├── query │ └── apiSlice.ts │ ├── requiredInfoSlice.ts │ ├── store.ts │ └── userSlice.ts ├── scripts └── reset-project.js ├── tsconfig.json └── types └── index.ts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .expo/ 3 | dist/ 4 | npm-debug.* 5 | *.jks 6 | *.p8 7 | *.p12 8 | *.key 9 | *.mobileprovision 10 | *.orig.* 11 | web-build/ 12 | .vscode/ 13 | # macOS 14 | .DS_Store 15 | 16 | # @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb 17 | # The following patterns were generated by expo-cli 18 | 19 | expo-env.d.ts 20 | # @end expo-cli -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to your Expo app 👋 2 | 3 | This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app). 4 | 5 | ## Get started 6 | 7 | 1. Install dependencies 8 | 9 | ```bash 10 | npm install 11 | ``` 12 | 13 | 2. Start the app 14 | 15 | ```bash 16 | npx expo start 17 | ``` 18 | 19 | In the output, you'll find options to open the app in a 20 | 21 | - [development build](https://docs.expo.dev/develop/development-builds/introduction/) 22 | - [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/) 23 | - [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/) 24 | - [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo 25 | 26 | You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction). 27 | 28 | ## Get a fresh project 29 | 30 | When you're ready, run: 31 | 32 | ```bash 33 | npm run reset-project 34 | ``` 35 | 36 | This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing. 37 | 38 | ## Learn more 39 | 40 | To learn more about developing your project with Expo, look at the following resources: 41 | 42 | - [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides). 43 | - [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web. 44 | 45 | ## Join the community 46 | 47 | Join our community of developers creating universal apps. 48 | 49 | - [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute. 50 | - [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions. 51 | -------------------------------------------------------------------------------- /api/index.ts: -------------------------------------------------------------------------------- 1 | import { API_URL } from "@/config"; 2 | import * as SecureStore from "expo-secure-store"; 3 | 4 | async function fetchWithRetry(url: string, options = {}, retries = 5) { 5 | try { 6 | // Try making the API call 7 | const response = await fetch(url, options); 8 | // console.log("Response in api", response.ok); 9 | 10 | // If the response is not OK, throw an error to trigger retry 11 | if (!response.ok) { 12 | console.log("Response.ok is not true", response); 13 | 14 | throw new Error(`Request failed with status ${response.status}`); 15 | } 16 | 17 | // If token is expired, reponse status is received 18 | // Sign out logic 19 | 20 | // Return the successful response 21 | return response.json(); // or return response.text(), response.blob(), etc., based on your needs 22 | } catch (error) { 23 | if (retries > 0) { 24 | console.warn(`Retrying... (${retries} retries left) and url is ${url}`); 25 | 26 | // Wait for the specified delay before retrying 27 | await new Promise((resolve) => setTimeout(resolve, 1000)); 28 | 29 | // Retry the API call recursively 30 | return fetchWithRetry(url, options, retries - 1); 31 | } else { 32 | // If all retries fail, rethrow the error 33 | console.error("All retries failed"); 34 | throw error; 35 | } 36 | } 37 | } 38 | 39 | export const fetchApi = async ( 40 | endpoint: string, 41 | method = "GET", 42 | token = "Hey it's me, baby.", // Fake token 43 | data = {} 44 | ) => { 45 | // const url = "http://localhost:4000/products"; 46 | const getToken = await SecureStore.getItemAsync("token"); 47 | console.log("Token --------", getToken); 48 | 49 | const url = API_URL + endpoint; 50 | const headers = { 51 | accept: "application/json", 52 | Authorization: "Bearer " + token, 53 | }; 54 | const options = 55 | Object.keys(data).length === 0 56 | ? { 57 | method, 58 | headers, 59 | } 60 | : { 61 | method, 62 | headers, 63 | body: JSON.stringify(data), 64 | }; 65 | try { 66 | const response = await fetchWithRetry(url, options, 5); // 3 retries with 1-second delay 67 | return response; 68 | } catch (error) { 69 | console.error("Failed to fetch API:", error); 70 | } 71 | 72 | // try { 73 | // const res = await fetch(url, options); 74 | 75 | // if (!res.ok) { 76 | // throw new Error("Failed to fetch api"); 77 | // } 78 | 79 | // const response = await res.json(); 80 | // // console.log("Response", response); 81 | // return response; 82 | // } catch (error) { 83 | // console.error(error); 84 | // } 85 | }; 86 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "mdc-rne", 4 | "slug": "mdc-rne", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/images/icon.png", 8 | "scheme": "myapp", 9 | "userInterfaceStyle": "automatic", 10 | "splash": { 11 | "image": "./assets/images/splash.png", 12 | "resizeMode": "contain", 13 | "backgroundColor": "#ffffff" 14 | }, 15 | "ios": { 16 | "supportsTablet": true 17 | }, 18 | "android": { 19 | "adaptiveIcon": { 20 | "foregroundImage": "./assets/images/adaptive-icon.png", 21 | "backgroundColor": "#ffffff" 22 | } 23 | }, 24 | "web": { 25 | "bundler": "metro", 26 | "output": "static", 27 | "favicon": "./assets/images/favicon.png" 28 | }, 29 | "plugins": [ 30 | "expo-router", 31 | "expo-secure-store" 32 | ], 33 | "experiments": { 34 | "typedRoutes": true 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/(app)/(tabs)/(home)/_layout.tsx: -------------------------------------------------------------------------------- 1 | import { Stack } from "expo-router"; 2 | 3 | export default Stack; -------------------------------------------------------------------------------- /app/(app)/(tabs)/(home)/detail.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | View, 3 | Text, 4 | Pressable, 5 | Animated, 6 | Dimensions, 7 | ScrollView, 8 | StyleSheet, 9 | } from "react-native"; 10 | import React, { useState, useCallback, useMemo, useRef } from "react"; 11 | import { Stack, useLocalSearchParams, useRouter } from "expo-router"; 12 | import { useAppDispatch, useAppSelector } from "@/hooks/useRedux"; 13 | import Ionicons from "@expo/vector-icons/Ionicons"; 14 | import BottomSheet, { 15 | BottomSheetFlatList, 16 | BottomSheetBackdrop, 17 | } from "@gorhom/bottom-sheet"; 18 | import { Picker } from "@react-native-picker/picker"; 19 | 20 | import Cart from "@/components/shop/Cart"; 21 | import ViewPager from "@/components/shop/ViewPager"; 22 | import { selectItems } from "@/data"; 23 | import { ProductType, Color, Size, Sample } from "@/types"; 24 | import { 25 | fetchProducts, 26 | updateFavouriteApi, 27 | selectProductById, 28 | selectProductIds, 29 | selectTotalProducts, 30 | selectAllProducts, 31 | selectProductEntities, 32 | } from "@/providers/redux/productSlice"; 33 | import { addCart } from "@/providers/redux/cartSlice"; 34 | import Toast from "react-native-root-toast"; 35 | 36 | const { width, height } = Dimensions.get("window"); 37 | 38 | export default function DetailScreen() { 39 | const { id } = useLocalSearchParams(); 40 | const router = useRouter(); 41 | const dispatch = useAppDispatch(); 42 | const product = useAppSelector((state) => 43 | selectProductById(state, id as string) 44 | ); 45 | const { cartList } = useAppSelector((state) => state.carts); 46 | 47 | const { 48 | colors, 49 | sizes, 50 | sample, 51 | }: { colors: Color[]; sizes: Size[]; sample: Sample[] } = useAppSelector( 52 | (state) => state.requiredInfo 53 | ); 54 | 55 | const [selectedColor, setSelectedColor] = useState(); 56 | const [selectedSize, setSelectedSize] = useState(); 57 | 58 | let cartArray: any[] = []; 59 | if (cartList.length > 0) { 60 | const list = cartList.find((item: any) => item.id == product.id); 61 | if (list) { 62 | cartArray = list.items; 63 | } 64 | } 65 | 66 | const [quantity, setQuantity] = useState(1); 67 | const [cart, setCart] = useState(cartArray); 68 | 69 | const increase = () => { 70 | if (!selectedColor || !selectedSize) { 71 | return Toast.show("Please choose color & size.", { 72 | duration: Toast.durations.LONG, 73 | }); 74 | } 75 | setQuantity((q) => q + 1); 76 | }; 77 | 78 | const decrease = () => { 79 | if (quantity == 1) return; 80 | setQuantity((q) => q - 1); 81 | }; 82 | 83 | const addToCart = () => { 84 | if (!selectedColor || !selectedSize) { 85 | return Toast.show("Please choose color & size.", { 86 | duration: Toast.durations.LONG, 87 | }); 88 | } 89 | 90 | setCart((prev) => [ 91 | { id: new Date().getTime(), selectedColor, selectedSize, quantity }, 92 | ...prev, 93 | ]); 94 | setQuantity(1); 95 | // Add To Dedux 96 | // const cartItem = { 97 | // id: product.id, 98 | // title: product.title, 99 | // price: product.price, 100 | // image: product.image, 101 | // items: [ 102 | // ...cart, 103 | // { id: new Date().getTime(), selectedColor, selectedSize, quantity }, 104 | // ], 105 | // }; 106 | // dispatch(addCart(cartItem)); 107 | }; 108 | 109 | const removeCart = (id: number) => { 110 | setCart((prev) => prev.filter((item) => item.id !== id)); 111 | // Update To Dedux 112 | // const cartItem = { 113 | // id: product.id, 114 | // title: product.title, 115 | // price: product.price, 116 | // image: product.image, 117 | // items: cart.filter((item) => item.id !== id), 118 | // }; 119 | // dispatch(addCart(cartItem)); 120 | }; 121 | 122 | // ref 123 | const bottomSheetRef = useRef(null); 124 | 125 | const handleClosePress = () => bottomSheetRef.current?.close(); 126 | const handleOpenPress = () => bottomSheetRef.current?.snapToIndex(1); 127 | 128 | // callbacks 129 | const handleSheetChanges = useCallback((index: number) => { 130 | // console.log("handleSheetChanges", index); 131 | }, []); 132 | 133 | const snapPoints = useMemo(() => ["50%", "75%", "100%"], []); 134 | 135 | // renders 136 | const renderBackdrop = useCallback( 137 | (props: any) => ( 138 | 144 | ), 145 | [] 146 | ); 147 | 148 | // render 149 | const renderSheetItem = useCallback( 150 | ({ item }: any) => ( 151 | 152 | 153 | {item.selectedColor.toUpperCase()} - {item.selectedSize} - ( $ 154 | {(product.price * item.quantity).toFixed(2)} ) 155 | 156 | ( {item.quantity} ) 157 | removeCart(item.id)}> 158 | 164 | 165 | 166 | ), 167 | [] 168 | ); 169 | 170 | const addCartToRedux = () => { 171 | if (cart.length == 0) { 172 | return Toast.show("Please choose color & size.", { 173 | duration: Toast.durations.LONG, 174 | }); 175 | } 176 | 177 | const cartItem = { 178 | id: product.id, 179 | title: product.title, 180 | price: product.price, 181 | image: product.image, 182 | items: cart, 183 | }; 184 | dispatch(addCart(cartItem)); 185 | router.back(); 186 | }; 187 | 188 | const buyNow = () => { 189 | if (cart.length == 0) { 190 | return Toast.show("Please choose color & size.", { 191 | duration: Toast.durations.LONG, 192 | }); 193 | } 194 | 195 | const cartItem = { 196 | id: product.id, 197 | title: product.title, 198 | price: product.price, 199 | image: product.image, 200 | items: cart, 201 | }; 202 | dispatch(addCart(cartItem)); 203 | router.push("/cart"); 204 | }; 205 | 206 | const ColorBox = ({ 207 | id, 208 | name, 209 | bgColor, 210 | stock, 211 | }: { 212 | id: string; 213 | name: string; 214 | bgColor: string; 215 | stock: boolean; 216 | }) => ( 217 | 224 | 229 | 230 | ); 231 | const SizeBox = ({ 232 | id, 233 | name, 234 | stock, 235 | }: { 236 | id: string; 237 | name: string; 238 | stock: boolean; 239 | }) => ( 240 | 249 | 252 | {name} 253 | 254 | 255 | ); 256 | 257 | const addToFavourite = async () => { 258 | try { 259 | const data = { id: product.id, data: { favourite: !product.favourite } }; 260 | // const data = { id: "abc", data: { favourite: !product.favourite } }; 261 | await dispatch(updateFavouriteApi(data)).unwrap(); 262 | } catch (error: any) { 263 | Toast.show(error, { 264 | duration: Toast.durations.SHORT, 265 | }); 266 | } 267 | }; 268 | 269 | return ( 270 | 271 | ( 278 | 279 | 280 | 281 | ), 282 | }} 283 | /> 284 | 288 | 289 | 290 | 291 | 292 | {product.brand} 293 | 299 | {product.star} 300 | ({product.quantity}) 301 | 302 | 303 | 309 | 310 | 311 | {product.title} 312 | 313 | {product.price.toFixed(2)} 314 | {product.discount.toFixed(2)} 315 | 316 | {product.description} 317 | 600 320 | ? { 321 | flexDirection: "row", 322 | gap: 40, 323 | } 324 | : { flexDirection: "column" } 325 | } 326 | > 327 | 328 | Choose Colors 329 | 330 | {selectItems.colors.map((color) => ( 331 | 332 | ))} 333 | 334 | 335 | 336 | Size 337 | 338 | {selectItems.sizes.map((size) => ( 339 | 340 | ))} 341 | 342 | 343 | 344 | {cart.length > 0 && ( 345 | Order Lists 346 | )} 347 | {cart.length > 0 && 348 | cart.map((item) => ( 349 | 350 | 351 | {item.selectedColor.toUpperCase()} - {item.selectedSize} - ( $ 352 | {(product.price * item.quantity).toFixed(2)} ) 353 | 354 | ( {item.quantity} ) 355 | 356 | ))} 357 | 358 | 359 | 360 | 361 | 362 | 363 | ADD TO CART 364 | 365 | 369 | BUY NOW 370 | 371 | 372 | 382 | 387 | 388 | Choose color 389 | 390 | 391 | Choose size 392 | 393 | 394 | 395 | 398 | setSelectedColor(itemValue) 399 | } 400 | // mode="dropdown" 401 | style={{ width: "45%" }} 402 | itemStyle={{ fontSize: 14, fontWeight: "600" }} 403 | > 404 | {colors.map((color) => { 405 | if (!color.stock) return; 406 | return ( 407 | 412 | ); 413 | })} 414 | 415 | setSelectedSize(itemValue)} 418 | // mode="dropdown" 419 | style={{ width: "45%" }} 420 | itemStyle={{ fontSize: 14, fontWeight: "600" }} 421 | > 422 | {sizes.map((size) => { 423 | if (!size.stock) return; 424 | return ( 425 | 430 | ); 431 | })} 432 | 433 | 434 | 442 | 443 | {colors.map((item) => 444 | item.name === selectedColor ? ( 445 | 446 | ) : null 447 | )} 448 | {""} 449 | {sizes.map((item) => 450 | item.name === selectedSize ? ( 451 | 452 | ) : null 453 | )} 454 | 455 | 456 | 457 | + 458 | 459 | {quantity} 460 | 464 | - 465 | 466 | 467 | 468 | 474 | 475 | 476 | {cart.length > 0 && ( 477 | index.toString()} 480 | renderItem={renderSheetItem} 481 | contentContainerStyle={{ zIndex: 1, alignItems: "center" }} 482 | /> 483 | )} 484 | 485 | 486 | ); 487 | } 488 | 489 | const styles = StyleSheet.create({ 490 | container: { 491 | minHeight: "100%", 492 | backgroundColor: "white", 493 | }, 494 | detailContiner: { 495 | marginTop: 17, 496 | marginHorizontal: 20, 497 | }, 498 | row: { 499 | flexDirection: "row", 500 | }, 501 | brandContainer: { 502 | justifyContent: "space-between", 503 | }, 504 | brand: { 505 | color: "gray", 506 | fontWeight: "600", 507 | marginRight: 7, 508 | }, 509 | star: { 510 | marginHorizontal: 2, 511 | fontSize: 13, 512 | }, 513 | quantity: { 514 | color: "gray", 515 | fontSize: 13, 516 | }, 517 | title: { 518 | marginVertical: 7, 519 | fontSize: 15, 520 | fontWeight: "500", 521 | }, 522 | price: { 523 | marginRight: 7, 524 | fontSize: 15, 525 | color: "#007618", 526 | fontWeight: "600", 527 | }, 528 | discount: { 529 | color: "gray", 530 | textDecorationLine: "line-through", 531 | }, 532 | description: { 533 | marginTop: 15, 534 | lineHeight: 22, 535 | opacity: 0.7, 536 | }, 537 | boxTitle: { 538 | marginTop: 17, 539 | marginBottom: 10, 540 | fontSize: 13, 541 | }, 542 | box: { 543 | flexDirection: "row", 544 | gap: 12, 545 | flexWrap: "wrap", 546 | }, 547 | circle: { 548 | width: 30, 549 | height: 30, 550 | borderRadius: 15, 551 | justifyContent: "center", 552 | alignItems: "center", 553 | }, 554 | btnContainer: { 555 | flexDirection: "row", 556 | position: "absolute", 557 | bottom: 10, 558 | width: "100%", 559 | justifyContent: "center", 560 | alignItems: "center", 561 | gap: 17, 562 | }, 563 | button: { 564 | width: width / 2.5, 565 | flexDirection: "row", 566 | justifyContent: "center", 567 | alignItems: "center", 568 | gap: 5, 569 | borderWidth: 0.7, 570 | paddingVertical: 10, 571 | paddingHorizontal: 25, 572 | borderRadius: 7, 573 | backgroundColor: "white", 574 | }, 575 | btnText: { 576 | fontWeight: "700", 577 | }, 578 | contentContainer: { 579 | flex: 1, 580 | alignItems: "center", 581 | }, 582 | modalTitleContainer: { 583 | width: "50%", 584 | }, 585 | modalTitle: { 586 | textAlign: "center", 587 | fontWeight: "700", 588 | fontSize: 15, 589 | color: "#000000", 590 | paddingTop: 7, 591 | marginHorizontal: 4, 592 | }, 593 | order: { 594 | marginVertical: 15, 595 | fontWeight: "bold", 596 | opacity: 0.7, 597 | }, 598 | itemContainer: { 599 | flexDirection: "row", 600 | justifyContent: "space-between", 601 | paddingHorizontal: 30, 602 | paddingVertical: 5, 603 | borderRadius: 5, 604 | marginBottom: 5, 605 | backgroundColor: "#00000007", 606 | }, 607 | resultContainer: { 608 | flexDirection: "row", 609 | justifyContent: "center", 610 | alignItems: "center", 611 | // borderWidth: 0.5, 612 | backgroundColor: "#00000007", 613 | paddingVertical: 10, 614 | paddingHorizontal: 30, 615 | marginLeft: 10, 616 | borderRadius: 10, 617 | }, 618 | colorModal: { 619 | width: 20, 620 | height: 20, 621 | borderRadius: 10, 622 | borderWidth: 0.2, 623 | borderColor: "gray", 624 | }, 625 | spinner: { 626 | width: 26, 627 | height: 26, 628 | backgroundColor: "#007618", 629 | borderRadius: 13, 630 | justifyContent: "center", 631 | alignItems: "center", 632 | // marginRight: 5, 633 | }, 634 | spinnerText: { 635 | color: "white", 636 | fontWeight: "bold", 637 | fontSize: 17, 638 | }, 639 | checkTitle: { 640 | marginTop: 17, 641 | marginBottom: 10, 642 | fontSize: 13, 643 | }, 644 | }); 645 | -------------------------------------------------------------------------------- /app/(app)/(tabs)/(home)/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | View, 3 | Text, 4 | StyleSheet, 5 | Dimensions, 6 | Pressable, 7 | FlatList, 8 | ScrollView, 9 | } from "react-native"; 10 | import React, { useEffect, useState, useRef } from "react"; 11 | import { Link, useNavigation, useRouter } from "expo-router"; 12 | import { SafeAreaView } from "react-native-safe-area-context"; 13 | import { Image } from "expo-image"; 14 | import { FlashList } from "@shopify/flash-list"; 15 | import { StatusBar } from "expo-status-bar"; 16 | import { useScrollToTop } from "@react-navigation/native"; 17 | 18 | import { useAppDispatch, useAppSelector } from "@/hooks/useRedux"; 19 | import { 20 | fetchProducts, 21 | updateFavouriteApi, 22 | updateProduct, 23 | selectProductById, 24 | selectAllProducts, 25 | } from "@/providers/redux/productSlice"; 26 | import { fetchRequiredInfo } from "@/providers/redux/requiredInfoSlice"; 27 | import { ProductType, CategoryType } from "@/types"; 28 | import Toast from "react-native-root-toast"; 29 | 30 | import Cart from "@/components/shop/Cart"; 31 | import Title from "@/components/shop/Title"; 32 | import Category from "@/components/shop/Category"; 33 | import Product from "@/components/shop/Product"; 34 | 35 | const blurhash = 36 | "|rF?hV%2WCj[ayj[a|j[az_NaeWBj@ayfRayfQfQM{M|azj[azf6fQfQfQIpWXofj[ayj[j[fQayWCoeoeaya}j[ayfQa{oLj?j[WVj[ayayj[fQoff7azayj[ayj[j[ayofayayayj[fQj[ayayj[ayfjj[j[ayjuayj["; 37 | 38 | export default function HomeScreen() { 39 | const { width, height } = Dimensions.get("window"); 40 | const navigation = useNavigation(); 41 | const [select, setSelect] = useState("uuid1"); 42 | // const [data, setData] = useState(); 43 | const scrollRef = useRef(null); 44 | useScrollToTop(scrollRef); 45 | const router = useRouter(); 46 | 47 | const dispatch = useAppDispatch(); 48 | const products = useAppSelector(selectAllProducts); 49 | const productsLoading = useAppSelector((state) => state.products.loading); 50 | const errorStatus = useAppSelector((state) => state.products.error); 51 | const categories: CategoryType[] = useAppSelector( 52 | (state) => state.requiredInfo.categories 53 | ); 54 | const productLists = products.filter( 55 | (product) => product.categories_id === select 56 | ); 57 | 58 | useEffect(() => { 59 | navigation.setOptions({ headerShown: false }); 60 | dispatch(fetchProducts()); 61 | }, [navigation]); 62 | 63 | if (productsLoading) { 64 | return Loading...; 65 | } 66 | 67 | if (categories.length == 0) { 68 | return ( 69 | 70 | Data request has failed! 71 | dispatch(fetchRequiredInfo())} 73 | style={styles.btnError} 74 | > 75 | Try again 76 | 77 | 78 | ); 79 | } 80 | 81 | if (errorStatus) { 82 | return ( 83 | 84 | Network Connection Failed! 85 | dispatch(fetchProducts())} 87 | style={styles.btnError} 88 | > 89 | Try again 90 | 91 | 92 | ); 93 | } 94 | 95 | const onSelectHandler = (name: string) => { 96 | setSelect(name); 97 | }; 98 | 99 | const onPressToTop = () => { 100 | scrollRef.current?.scrollTo({ 101 | y: 0, 102 | animated: true, 103 | }); 104 | }; 105 | 106 | const saveProductToRedux = (id: string) => { 107 | router.push({ 108 | pathname: "/detail", 109 | params: { id }, // Data passed as query parameters 110 | }); 111 | }; 112 | 113 | const addToFavourite = async (item: ProductType) => { 114 | try { 115 | const data = { id: item.id, data: { favourite: !item.favourite } }; 116 | // const data = { id: "abc", data: { favourite: !item.favourite } }; 117 | await dispatch(updateFavouriteApi(data)).unwrap(); 118 | } catch (error: any) { 119 | // console.log("Error-----", error); 120 | Toast.show(error, { 121 | duration: Toast.durations.SHORT, 122 | }); 123 | } 124 | }; 125 | 126 | return ( 127 | 128 | 129 | 130 | 131 | 138 | 139 | router.navigate("/cart")}> 140 | 141 | 142 | 143 | 144 | 151 | 152 | 153 | <FlashList 154 | data={categories} 155 | extraData={select} 156 | horizontal 157 | renderItem={({ item }) => ( 158 | <Category {...item} onSelect={onSelectHandler} select={select} /> 159 | )} 160 | estimatedItemSize={80} 161 | showsHorizontalScrollIndicator={false} 162 | /> 163 | <Text>{""}</Text> 164 | <Title title="Recommended for You" action="See All" /> 165 | <FlashList 166 | data={productLists} 167 | horizontal 168 | renderItem={({ item }) => ( 169 | <Product 170 | {...item} 171 | onCall={() => saveProductToRedux(item.id)} 172 | onAdd={() => addToFavourite(item)} 173 | /> 174 | )} 175 | estimatedItemSize={80} 176 | showsHorizontalScrollIndicator={false} 177 | /> 178 | <Title title="Popular Lists for You" action="See All" /> 179 | <FlashList 180 | data={productLists} 181 | horizontal 182 | renderItem={({ item }) => ( 183 | <Product 184 | {...item} 185 | onCall={() => saveProductToRedux(item.id)} 186 | onAdd={() => addToFavourite(item)} 187 | /> 188 | )} 189 | estimatedItemSize={80} 190 | showsHorizontalScrollIndicator={false} 191 | /> 192 | <View style={{ marginBottom: 100 }} /> 193 | </View> 194 | </ScrollView> 195 | </SafeAreaView> 196 | ); 197 | } 198 | 199 | const styles = StyleSheet.create({ 200 | container: { 201 | flexDirection: "row", 202 | justifyContent: "space-between", 203 | marginBottom: 10, 204 | marginRight: 15, 205 | }, 206 | image: { 207 | width: 50, 208 | height: 25, 209 | marginLeft: 15, 210 | }, 211 | banner: { 212 | width: "100%", 213 | aspectRatio: 20 / 9, 214 | }, 215 | btnError: { 216 | marginTop: 10, 217 | paddingVertical: 5, 218 | paddingHorizontal: 10, 219 | borderColor: "black", 220 | borderWidth: 0.5, 221 | borderRadius: 5, 222 | }, 223 | }); 224 | -------------------------------------------------------------------------------- /app/(app)/(tabs)/_layout.tsx: -------------------------------------------------------------------------------- 1 | import { Tabs } from "expo-router"; 2 | import React, { useEffect } from "react"; 3 | 4 | import { TabBarIcon } from "@/components/navigation/TabBarIcon"; 5 | import { Colors } from "@/constants/Colors"; 6 | import { useColorScheme } from "@/hooks/useColorScheme"; 7 | 8 | import { useAppDispatch } from "@/hooks/useRedux"; 9 | import { fetchRequiredInfo } from "@/providers/redux/requiredInfoSlice"; 10 | import Toast from "react-native-root-toast"; 11 | 12 | export default function TabLayout() { 13 | const colorScheme = useColorScheme(); 14 | const dispatch = useAppDispatch(); 15 | 16 | useEffect(() => { 17 | // dispatch(fetchRequiredInfo()); 18 | fetchInfo(); 19 | }, []); 20 | 21 | const fetchInfo = async () => { 22 | try { 23 | await dispatch(fetchRequiredInfo()).unwrap(); 24 | } catch (error: any) { 25 | // console.log("Error-----", error); 26 | Toast.show(error, { 27 | duration: Toast.durations.LONG, 28 | }); 29 | } 30 | }; 31 | 32 | return ( 33 | <Tabs 34 | screenOptions={{ 35 | tabBarActiveTintColor: Colors[colorScheme ?? "light"].tint, 36 | headerShown: false, 37 | }} 38 | > 39 | <Tabs.Screen 40 | name="(home)" 41 | options={{ 42 | title: "Home", 43 | tabBarIcon: ({ color, focused }) => ( 44 | <TabBarIcon 45 | name={focused ? "home" : "home-outline"} 46 | color={color} 47 | /> 48 | ), 49 | }} 50 | /> 51 | <Tabs.Screen 52 | name="explore" 53 | options={{ 54 | title: "Explore", 55 | tabBarIcon: ({ color, focused }) => ( 56 | <TabBarIcon 57 | name={focused ? "search" : "search-outline"} 58 | color={color} 59 | /> 60 | ), 61 | }} 62 | /> 63 | <Tabs.Screen 64 | name="cart" 65 | options={{ 66 | title: "Cart", 67 | tabBarIcon: ({ color, focused }) => ( 68 | <TabBarIcon 69 | name={focused ? "cart" : "cart-outline"} 70 | color={color} 71 | /> 72 | ), 73 | }} 74 | /> 75 | <Tabs.Screen 76 | name="profile" 77 | options={{ 78 | title: "Profile", 79 | tabBarIcon: ({ color, focused }) => ( 80 | <TabBarIcon 81 | name={focused ? "person" : "person-outline"} 82 | color={color} 83 | /> 84 | ), 85 | }} 86 | /> 87 | </Tabs> 88 | ); 89 | } 90 | -------------------------------------------------------------------------------- /app/(app)/(tabs)/cart.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | StyleSheet, 3 | View, 4 | Text, 5 | FlatList, 6 | Pressable, 7 | Alert, 8 | } from "react-native"; 9 | import { SafeAreaView } from "react-native-safe-area-context"; 10 | import { Image } from "expo-image"; 11 | import MaterialIcons from "@expo/vector-icons/MaterialIcons"; 12 | import LottieView from "lottie-react-native"; 13 | import { API_URL } from "@/config"; 14 | 15 | import { useAppDispatch, useAppSelector } from "@/hooks/useRedux"; 16 | import { updateCart, deleteCart } from "@/providers/redux/cartSlice"; 17 | 18 | const blurhash = 19 | "|rF?hV%2WCj[ayj[a|j[az_NaeWBj@ayfRayfQfQM{M|azj[azf6fQfQfQIpWXofj[ayj[j[fQayWCoeoeaya}j[ayfQa{oLj?j[WVj[ayayj[fQoff7azayj[ayj[j[ayofayayayj[fQj[ayayj[ayfjj[j[ayjuayj["; 20 | 21 | const CartItem = ({ 22 | id, 23 | title, 24 | price, 25 | image, 26 | items, 27 | dispatch, 28 | onRemove, 29 | }: { 30 | id: number; 31 | title: string; 32 | price: number; 33 | image: any; 34 | items: any[]; 35 | dispatch: any; 36 | onRemove: (id: number, itemId: number, title: string) => void, 37 | }) => { 38 | const changeCart = (id: number, itemId: number, quantity: number) => { 39 | if (quantity < 1) { 40 | return; 41 | } 42 | dispatch( 43 | updateCart({ 44 | id, 45 | itemId, 46 | quantity, 47 | }) 48 | ); 49 | }; 50 | 51 | const imageUri = 52 | { uri: `${API_URL + image}` }; 53 | 54 | return ( 55 | <> 56 | {items.length > 1 ? ( 57 | items.map((item) => ( 58 | <View style={styles.container} key={item.id}> 59 | <View style={{ flexDirection: "row", gap: 15 }}> 60 | <Image 61 | style={styles.image} 62 | source={imageUri} 63 | placeholder={{ blurhash }} 64 | contentFit="cover" 65 | transition={1000} 66 | /> 67 | <View> 68 | <Text style={styles.title}> 69 | {title.length > 35 ? title.substring(0, 34) + "..." : title} 70 | </Text> 71 | <Text style={styles.select}> 72 | Color - [ {item.selectedColor} ] & Size - [{" "} 73 | {item.selectedSize} ] 74 | </Text> 75 | <View style={{ flexDirection: "row" }}> 76 | <Text style={styles.price}> 77 | ${(price * item.quantity).toFixed(2)} 78 | </Text> 79 | <Pressable style={{ flexDirection: "row" }} onPress={() => onRemove(id, item.id, title)}> 80 | <MaterialIcons 81 | name="delete-forever" 82 | size={20} 83 | color="#E06237" 84 | style={{ alignSelf: "flex-end" }} 85 | /> 86 | <Text style={styles.delete}>Delete</Text> 87 | </Pressable> 88 | </View> 89 | </View> 90 | </View> 91 | <View style={{ alignItems: "center" }}> 92 | <Pressable 93 | style={styles.spinner} 94 | onPress={() => changeCart(id, item.id, item.quantity + 1)} 95 | > 96 | <Text style={styles.spinnerText}>+</Text> 97 | </Pressable> 98 | <Text style={{ marginHorizontal: 15 }}> {item.quantity} </Text> 99 | <Pressable 100 | style={[styles.spinner, { backgroundColor: "#00000060" }]} 101 | onPress={() => changeCart(id, item.id, item.quantity - 1)} 102 | > 103 | <Text style={styles.spinnerText}>-</Text> 104 | </Pressable> 105 | </View> 106 | </View> 107 | )) 108 | ) : ( 109 | <View style={styles.container}> 110 | <View style={{ flexDirection: "row", gap: 15 }}> 111 | <Image 112 | style={styles.image} 113 | source={imageUri} 114 | placeholder={{ blurhash }} 115 | contentFit="cover" 116 | transition={1000} 117 | /> 118 | <View> 119 | <Text style={styles.title}> 120 | {title.length > 35 ? title.substring(0, 34) + "..." : title} 121 | </Text> 122 | <Text style={styles.select}> 123 | Color - [ {items[0].selectedColor} ] & Size - [{" "} 124 | {items[0].selectedSize} ] 125 | </Text> 126 | <View style={{ flexDirection: "row" }}> 127 | <Text style={styles.price}> 128 | ${(price * items[0].quantity).toFixed(2)} 129 | </Text> 130 | <Pressable style={{ flexDirection: "row" }} onPress={() => onRemove(id, items[0].id, title)}> 131 | <MaterialIcons 132 | name="delete-forever" 133 | size={20} 134 | color="#E06237" 135 | style={{ alignSelf: "flex-end" }} 136 | /> 137 | <Text style={styles.delete}>Delete</Text> 138 | </Pressable> 139 | </View> 140 | </View> 141 | </View> 142 | <View style={{ alignItems: "center" }}> 143 | <Pressable 144 | style={styles.spinner} 145 | onPress={() => changeCart(id, items[0].id, items[0].quantity + 1)} 146 | > 147 | <Text style={styles.spinnerText}>+</Text> 148 | </Pressable> 149 | <Text style={{ marginHorizontal: 15 }}> {items[0].quantity} </Text> 150 | <Pressable 151 | style={[styles.spinner, { backgroundColor: "#00000060" }]} 152 | onPress={() => changeCart(id, items[0].id, items[0].quantity - 1)} 153 | > 154 | <Text style={styles.spinnerText}>-</Text> 155 | </Pressable> 156 | </View> 157 | </View> 158 | )} 159 | </> 160 | ); 161 | }; 162 | 163 | export default function CartScreen() { 164 | const dispatch = useAppDispatch(); // redux 165 | // const animation = useRef<LottieView>(null); 166 | // useEffect(() => { 167 | // // You can control the ref programmatically, rather than using autoPlay 168 | // // animation.current?.play(); 169 | // }, []); 170 | 171 | const carts = useAppSelector((state) => state.carts.cartList); 172 | 173 | let totalAmount = 0; 174 | if (carts.length > 0) { 175 | carts.forEach((cart: any) => { 176 | const total = cart.items.reduce( 177 | (total: any, item: any) => total + item.quantity, 178 | 0 179 | ); 180 | totalAmount += total * cart.price; 181 | }); 182 | } 183 | 184 | if (carts.length == 0) { 185 | return ( 186 | <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> 187 | <LottieView 188 | autoPlay 189 | // ref={animation} 190 | style={{ 191 | width: 200, 192 | height: 200, 193 | // backgroundColor: "#eee", 194 | }} 195 | // Find more Lottie files at https://lottiefiles.com/featured 196 | source={require("@/assets/images/shop/cart_empty.json")} 197 | /> 198 | <Text style={{ color: "gray", fontWeight: "bold" }}>Empty Cart</Text> 199 | </View> 200 | ); 201 | } 202 | 203 | const createTwoButtonAlert = (id: number, itemId: number, title: string) => 204 | Alert.alert("Delete it!", `Do you want to delete ${title} from cart?`, [ 205 | { 206 | text: "No", 207 | onPress: () => {}, 208 | style: "cancel", 209 | }, 210 | { text: "Yes", onPress: () => dispatch(deleteCart({id, itemId})) }, 211 | ]); 212 | 213 | return ( 214 | <SafeAreaView> 215 | <View style={styles.cartContainer}> 216 | <Text style={styles.currency}> 217 | $<Text style={styles.total}>{totalAmount.toFixed(2)}</Text> 218 | </Text> 219 | <Pressable style={styles.checkOut}> 220 | <MaterialIcons name="payments" size={24} color="white" /> 221 | <Text style={styles.checkTitle}>Check Out</Text> 222 | </Pressable> 223 | </View> 224 | <FlatList 225 | data={carts} 226 | extraData={carts} 227 | renderItem={({ item }) => <CartItem {...item} dispatch={dispatch} onRemove={createTwoButtonAlert}/>} 228 | showsVerticalScrollIndicator={false} 229 | /> 230 | </SafeAreaView> 231 | ); 232 | } 233 | 234 | const styles = StyleSheet.create({ 235 | cartContainer: { 236 | marginVertical: 15, 237 | paddingHorizontal: 20, 238 | flexDirection: "row", 239 | justifyContent: "space-between", 240 | }, 241 | currency: { 242 | fontSize: 16, 243 | fontWeight: "bold", 244 | color: "#007618", 245 | }, 246 | total: { 247 | fontSize: 24, 248 | fontWeight: "bold", 249 | }, 250 | checkOut: { 251 | flexDirection: "row", 252 | justifyContent: "center", 253 | alignItems: "center", 254 | gap: 7, 255 | backgroundColor: "#157ABE", 256 | paddingVertical: 10, 257 | paddingHorizontal: 20, 258 | borderRadius: 7, 259 | }, 260 | checkTitle: { 261 | color: "#fff", 262 | fontWeight: "bold", 263 | }, 264 | container: { 265 | width: "94%", 266 | flexDirection: "row", 267 | justifyContent: "space-between", 268 | alignItems: "center", 269 | marginHorizontal: "auto", 270 | backgroundColor: "#fff", 271 | padding: 12, 272 | borderRadius: 10, 273 | marginBottom: 5, 274 | }, 275 | image: { 276 | height: 60, 277 | aspectRatio: 3 / 4, 278 | borderRadius: 5, 279 | }, 280 | title: { 281 | marginBottom: 3, 282 | }, 283 | select: { 284 | color: "gray", 285 | fontWeight: "700", 286 | }, 287 | price: { 288 | fontSize: 16, 289 | fontWeight: "700", 290 | color: "#494D4D", 291 | marginTop: 5, 292 | marginRight: 20, 293 | }, 294 | delete: { 295 | fontSize: 14, 296 | fontWeight: "700", 297 | color: "#E06237", 298 | marginTop: 7, 299 | }, 300 | spinner: { 301 | width: 26, 302 | height: 26, 303 | backgroundColor: "#4CA049", 304 | borderRadius: 13, 305 | justifyContent: "center", 306 | alignItems: "center", 307 | // marginRight: 5, 308 | }, 309 | spinnerText: { 310 | color: "white", 311 | fontWeight: "bold", 312 | fontSize: 17, 313 | }, 314 | }); -------------------------------------------------------------------------------- /app/(app)/(tabs)/explore.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, View, Text, Pressable } from "react-native"; 2 | import { SafeAreaView } from "react-native-safe-area-context"; 3 | import { memo } from "react"; 4 | 5 | import { 6 | useGetUsersQuery, 7 | useUpdateUserMutation, 8 | } from "@/providers/redux/userSlice"; 9 | 10 | type UserType = { 11 | id: string; 12 | name: string; 13 | }; 14 | 15 | export default function ExploreScreen() { 16 | const { 17 | data: users, 18 | isLoading, 19 | isSuccess, 20 | isError, 21 | error, 22 | refetch, 23 | } = useGetUsersQuery("getUsers"); 24 | 25 | let content; 26 | if (isLoading) { 27 | content = <Text>"Loading..."</Text>; 28 | } else if (isSuccess) { 29 | console.log("Users-----", users); 30 | if (Object.keys(users.entities).length === 0) { 31 | return ( 32 | <View 33 | style={{ flex: 1, justifyContent: "center", alignItems: "center" }} 34 | > 35 | <Text>Data request has failed!</Text> 36 | <Pressable style={styles.btnError} onPress={refetch}> 37 | <Text>Try again</Text> 38 | </Pressable> 39 | </View> 40 | ); 41 | } 42 | 43 | // console.log("In expore -----", users); 44 | const { ids, entities } = users; // ids : ["uuid1", "uuid2",...], entities: {"uuid1": {id: "uuid1", "name": "David22"}, ...} 45 | content = ids.map((userId: string) => ( 46 | <UserItem key={userId} user={entities[userId]} /> 47 | )); 48 | } else if (isError) { 49 | content = <Text>An error occurs.</Text>; 50 | } 51 | 52 | return <SafeAreaView style={styles.titleContainer}>{content}</SafeAreaView>; 53 | } 54 | 55 | const UserItem = memo(({ user }: { user: UserType }) => { 56 | const [updateUser, { isLoading }] = useUpdateUserMutation(); 57 | console.log("User --------", user.id); 58 | 59 | const updateUserClick = async () => { 60 | try { 61 | await updateUser({ 62 | id: user.id, 63 | name: user.name + new Date().getSeconds(), 64 | }).unwrap(); 65 | } catch (error) { 66 | console.error("Failed to save the user", error); 67 | } 68 | }; 69 | 70 | return ( 71 | <Pressable onPress={updateUserClick} style={{ marginVertical: 11 }}> 72 | <Text style={styles.name}>{user.name}</Text> 73 | </Pressable> 74 | ); 75 | }); 76 | 77 | const styles = StyleSheet.create({ 78 | titleContainer: { 79 | height: "100%", 80 | backgroundColor: "#deeeef", 81 | alignItems: "center", 82 | justifyContent: "center", 83 | }, 84 | name: { 85 | fontSize: 17, 86 | fontWeight: "600", 87 | letterSpacing: 3, 88 | }, 89 | btnError: { 90 | marginTop: 10, 91 | paddingVertical: 5, 92 | paddingHorizontal: 10, 93 | borderColor: "black", 94 | borderWidth: 0.5, 95 | borderRadius: 5, 96 | }, 97 | }); 98 | -------------------------------------------------------------------------------- /app/(app)/(tabs)/profile.tsx: -------------------------------------------------------------------------------- 1 | import { View, Text, Pressable, StyleSheet } from "react-native"; 2 | import React from "react"; 3 | import { useSession } from "@/providers/ctx"; 4 | import { SafeAreaView } from "react-native-safe-area-context"; 5 | import Animated, { 6 | useSharedValue, 7 | withSpring, 8 | withTiming, 9 | useAnimatedStyle, 10 | runOnUI, 11 | } from "react-native-reanimated"; 12 | 13 | export default function profile() { 14 | const { signOut } = useSession(); 15 | const scale = useSharedValue(1); 16 | 17 | const animatedStyle = useAnimatedStyle(() => ({ 18 | transform: [{ scale: scale.value }], 19 | })); 20 | 21 | const onZoomIn = () => { 22 | "worklet"; 23 | scale.value = withTiming(scale.value - 0.5); 24 | }; 25 | const onZoomOut = () => { 26 | "worklet"; 27 | scale.value = withSpring(scale.value + 0.3); 28 | }; 29 | 30 | return ( 31 | <SafeAreaView style={{ alignItems: "center" }}> 32 | <Pressable onPress={signOut}> 33 | <Text>Sign Out</Text> 34 | </Pressable> 35 | <Animated.View style={[styles.box, animatedStyle]} /> 36 | <Pressable 37 | onPress={() => runOnUI(onZoomIn)()} 38 | style={{ marginBottom: 20 }} 39 | > 40 | <Text>Zoom In</Text> 41 | </Pressable> 42 | <Pressable onPress={() => runOnUI(onZoomOut)()}> 43 | <Text>Zoom Out</Text> 44 | </Pressable> 45 | </SafeAreaView> 46 | ); 47 | } 48 | 49 | const styles = StyleSheet.create({ 50 | box: { 51 | marginVertical: 200, 52 | width: 50, 53 | height: 50, 54 | borderRadius: 25, 55 | backgroundColor: "orange", 56 | }, 57 | }); 58 | -------------------------------------------------------------------------------- /app/(app)/_layout.tsx: -------------------------------------------------------------------------------- 1 | import { Text } from "react-native"; 2 | import { 3 | DarkTheme, 4 | DefaultTheme, 5 | ThemeProvider, 6 | } from "@react-navigation/native"; 7 | import { useFonts } from "expo-font"; 8 | import { Stack, Redirect } from "expo-router"; 9 | import * as SplashScreen from "expo-splash-screen"; 10 | import { useEffect } from "react"; 11 | import "react-native-reanimated"; 12 | 13 | import { useColorScheme } from "@/hooks/useColorScheme"; 14 | import { useSession } from "@/providers/ctx"; 15 | 16 | // Prevent the splash screen from auto-hiding before asset loading is complete. 17 | SplashScreen.preventAutoHideAsync(); 18 | 19 | export default function RootLayout() { 20 | const { session, isLoading } = useSession(); 21 | const colorScheme = useColorScheme(); 22 | const [loaded] = useFonts({ 23 | SpaceMono: require("../../assets/fonts/SpaceMono-Regular.ttf"), 24 | }); 25 | 26 | useEffect(() => { 27 | if (loaded) { 28 | SplashScreen.hideAsync(); 29 | } 30 | }, [loaded]); 31 | 32 | if (!loaded) { 33 | return null; 34 | } 35 | 36 | // You can keep the splash screen open, or render a loading screen like we do here. 37 | if (isLoading) { 38 | return <Text>Loading...</Text>; 39 | } 40 | 41 | // Only require authentication within the (app) group's layout as users 42 | // need to be able to access the (auth) group and sign in again. 43 | if (!session) { 44 | // On web, static rendering will stop here as the user is not authenticated 45 | // in the headless Node process that the pages are rendered in. 46 | return <Redirect href="/login" />; 47 | } 48 | 49 | return ( 50 | <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}> 51 | <Stack> 52 | <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> 53 | </Stack> 54 | </ThemeProvider> 55 | ); 56 | } 57 | -------------------------------------------------------------------------------- /app/+html.tsx: -------------------------------------------------------------------------------- 1 | import { ScrollViewStyleReset } from 'expo-router/html'; 2 | import { type PropsWithChildren } from 'react'; 3 | 4 | /** 5 | * This file is web-only and used to configure the root HTML for every web page during static rendering. 6 | * The contents of this function only run in Node.js environments and do not have access to the DOM or browser APIs. 7 | */ 8 | export default function Root({ children }: PropsWithChildren) { 9 | return ( 10 | <html lang="en"> 11 | <head> 12 | <meta charSet="utf-8" /> 13 | <meta httpEquiv="X-UA-Compatible" content="IE=edge" /> 14 | <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> 15 | 16 | {/* 17 | Disable body scrolling on web. This makes ScrollView components work closer to how they do on native. 18 | However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line. 19 | */} 20 | <ScrollViewStyleReset /> 21 | 22 | {/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */} 23 | <style dangerouslySetInnerHTML={{ __html: responsiveBackground }} /> 24 | {/* Add any additional <head> elements that you want globally available on web... */} 25 | </head> 26 | <body>{children}</body> 27 | </html> 28 | ); 29 | } 30 | 31 | const responsiveBackground = ` 32 | body { 33 | background-color: #fff; 34 | } 35 | @media (prefers-color-scheme: dark) { 36 | body { 37 | background-color: #000; 38 | } 39 | }`; 40 | -------------------------------------------------------------------------------- /app/+not-found.tsx: -------------------------------------------------------------------------------- 1 | import { Link, Stack } from 'expo-router'; 2 | import { StyleSheet } from 'react-native'; 3 | 4 | import { ThemedText } from '@/components/ThemedText'; 5 | import { ThemedView } from '@/components/ThemedView'; 6 | 7 | export default function NotFoundScreen() { 8 | return ( 9 | <> 10 | <Stack.Screen options={{ title: 'Oops!' }} /> 11 | <ThemedView style={styles.container}> 12 | <ThemedText type="title">This screen doesn't exist.</ThemedText> 13 | <Link href="/" style={styles.link}> 14 | <ThemedText type="link">Go to home screen!</ThemedText> 15 | </Link> 16 | </ThemedView> 17 | </> 18 | ); 19 | } 20 | 21 | const styles = StyleSheet.create({ 22 | container: { 23 | flex: 1, 24 | alignItems: 'center', 25 | justifyContent: 'center', 26 | padding: 20, 27 | }, 28 | link: { 29 | marginTop: 15, 30 | paddingVertical: 15, 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /app/_layout.tsx: -------------------------------------------------------------------------------- 1 | import { Slot } from "expo-router"; 2 | import { Provider } from "react-redux"; 3 | import { store } from "@/providers/redux/store"; 4 | import { RootSiblingParent } from "react-native-root-siblings"; 5 | import { GestureHandlerRootView } from "react-native-gesture-handler"; 6 | import { SessionProvider } from "@/providers/ctx"; 7 | 8 | export default function Root() { 9 | return ( 10 | <Provider store={store}> 11 | <RootSiblingParent> 12 | <GestureHandlerRootView> 13 | <SessionProvider> 14 | <Slot /> 15 | </SessionProvider> 16 | </GestureHandlerRootView> 17 | </RootSiblingParent> 18 | </Provider> 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /app/login.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, ScrollView, TextInput, Pressable } from "react-native"; 2 | import { SafeAreaView } from "react-native-safe-area-context"; 3 | import { router } from "expo-router"; 4 | import { Image } from "expo-image"; 5 | import { useForm, Controller } from "react-hook-form"; 6 | import Ionicons from "@expo/vector-icons/Ionicons"; 7 | 8 | import { ThemedText } from "@/components/ThemedText"; 9 | import { ThemedView } from "@/components/ThemedView"; 10 | 11 | import { useSession } from "@/providers/ctx"; 12 | 13 | const blurhash = 14 | "|rF?hV%2WCj[ayj[a|j[az_NaeWBj@ayfRayfQfQM{M|azj[azf6fQfQfQIpWXofj[ayj[j[fQayWCoeoeaya}j[ayfQa{oLj?j[WVj[ayayj[fQoff7azayj[ayj[j[ayofayayayj[fQj[ayayj[ayfjj[j[ayjuayj["; 15 | 16 | export default function Login() { 17 | const { signIn } = useSession(); 18 | 19 | const { 20 | register, 21 | setValue, 22 | handleSubmit, 23 | control, 24 | reset, 25 | formState: { errors }, 26 | } = useForm({ 27 | defaultValues: { 28 | phone: "", 29 | password: "", 30 | }, 31 | }); 32 | 33 | const onSubmit = async (formState: any) => { 34 | // console.log(formState); 35 | await signIn(formState); 36 | // Navigate after signing in. You may want to tweak this to ensure sign-in is 37 | // successful before navigating. 38 | router.replace("/"); 39 | }; 40 | 41 | // const onChange = (arg: any) => { 42 | // return { 43 | // value: arg.nativeEvent.text, 44 | // }; 45 | // }; 46 | 47 | return ( 48 | <SafeAreaView style={styles.container}> 49 | <ScrollView> 50 | <ThemedView style={styles.row}> 51 | <Image 52 | style={styles.image} 53 | source={require("@/assets/images/react-logo.png")} 54 | placeholder={{ blurhash }} 55 | contentFit="cover" 56 | transition={1000} 57 | /> 58 | <ThemedText style={styles.logoText}>Fashion</ThemedText> 59 | </ThemedView> 60 | <ThemedText style={styles.title}> 61 | Sign in {"\n"}to your Account 62 | </ThemedText> 63 | <ThemedText style={[styles.content, { marginBottom: 14 }]}> 64 | Enter your phone and password to log in 65 | </ThemedText> 66 | <ThemedText style={[styles.content, styles.label]}> 67 | Phone Number 68 | </ThemedText> 69 | <Controller 70 | control={control} 71 | render={({ field: { onChange, onBlur, value } }) => ( 72 | <TextInput 73 | style={styles.input} 74 | placeholder="0977******7" 75 | onBlur={onBlur} 76 | onChangeText={onChange} 77 | value={value} 78 | inputMode="numeric" 79 | maxLength={12} 80 | accessibilityLabel="inputLabel" 81 | accessibilityHint="inputError" 82 | /> 83 | )} 84 | name="phone" 85 | rules={{ required: true, minLength: 7 }} 86 | /> 87 | {errors.phone && ( 88 | <ThemedText style={styles.errorText}> 89 | Invalid Phone Number! 90 | </ThemedText> 91 | )} 92 | <ThemedText style={[styles.content, styles.label]}> 93 | Password 94 | <ThemedText style={styles.hintText}> 95 | {" "} 96 | ( Must be 8 digits. ) 97 | </ThemedText> 98 | </ThemedText> 99 | <Controller 100 | control={control} 101 | render={({ field: { onChange, onBlur, value } }) => ( 102 | <TextInput 103 | style={styles.input} 104 | placeholder="********" 105 | onBlur={onBlur} 106 | onChangeText={onChange} 107 | value={value} 108 | inputMode="numeric" 109 | maxLength={8} 110 | secureTextEntry 111 | accessibilityLabel="inputLabel" 112 | accessibilityHint="inputError" 113 | /> 114 | )} 115 | name="password" 116 | rules={{ required: true, minLength: 8 }} 117 | /> 118 | {errors.password && ( 119 | <ThemedText style={styles.errorText}>Invalid Password!</ThemedText> 120 | )} 121 | <Pressable> 122 | <ThemedText style={styles.forgetText}>Forgot Password ?</ThemedText> 123 | </Pressable> 124 | <Pressable 125 | style={[styles.input, { backgroundColor: "#2772DA" }]} 126 | onPress={handleSubmit(onSubmit)} 127 | > 128 | <ThemedText style={styles.btnText}>Log In</ThemedText> 129 | </Pressable> 130 | </ScrollView> 131 | </SafeAreaView> 132 | ); 133 | } 134 | 135 | const styles = StyleSheet.create({ 136 | container: { 137 | marginHorizontal: 20, 138 | }, 139 | row: { 140 | flexDirection: "row", 141 | justifyContent: "flex-end", 142 | marginTop: 12, 143 | gap: 5, 144 | }, 145 | image: { 146 | width: 20, 147 | height: 20, 148 | }, 149 | logoText: { 150 | fontSize: 18, 151 | fontWeight: "bold", 152 | }, 153 | title: { 154 | fontSize: 36, 155 | fontWeight: "bold", 156 | lineHeight: 46, 157 | }, 158 | content: { 159 | marginTop: 11, 160 | fontSize: 14, 161 | color: "#00000070", 162 | fontWeight: "700", 163 | }, 164 | label: { 165 | marginTop: 17, 166 | marginBottom: 3, 167 | }, 168 | input: { 169 | backgroundColor: "#ffffff", 170 | color: "#000", 171 | borderWidth: 0.5, 172 | borderColor: "#8C8C8C55", 173 | fontSize: 15, 174 | paddingVertical: 17, 175 | paddingHorizontal: 12, 176 | borderRadius: 9, 177 | }, 178 | hintText: { 179 | fontSize: 14, 180 | color: "#00000070", 181 | }, 182 | forgetText: { 183 | marginTop: 15, 184 | marginBottom: 24, 185 | fontSize: 14, 186 | fontWeight: "700", 187 | color: "#2772DA", 188 | textAlign: "right", 189 | }, 190 | btnText: { 191 | color: "#ffffff", 192 | textAlign: "center", 193 | fontWeight: "600", 194 | }, 195 | errorText: { 196 | paddingTop: 8, 197 | fontWeight: "bold", 198 | color: "#EF4444", 199 | }, 200 | }); 201 | -------------------------------------------------------------------------------- /assets/fonts/SpaceMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/fonts/SpaceMono-Regular.ttf -------------------------------------------------------------------------------- /assets/images/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/adaptive-icon.png -------------------------------------------------------------------------------- /assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/favicon.png -------------------------------------------------------------------------------- /assets/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/icon.png -------------------------------------------------------------------------------- /assets/images/partial-react-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/partial-react-logo.png -------------------------------------------------------------------------------- /assets/images/react-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/react-logo.png -------------------------------------------------------------------------------- /assets/images/react-logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/react-logo@2x.png -------------------------------------------------------------------------------- /assets/images/react-logo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/react-logo@3x.png -------------------------------------------------------------------------------- /assets/images/shop/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/adaptive-icon.png -------------------------------------------------------------------------------- /assets/images/shop/baby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/baby.png -------------------------------------------------------------------------------- /assets/images/shop/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/banner.png -------------------------------------------------------------------------------- /assets/images/shop/banner6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/banner6.png -------------------------------------------------------------------------------- /assets/images/shop/c1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/c1.png -------------------------------------------------------------------------------- /assets/images/shop/c2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/c2.png -------------------------------------------------------------------------------- /assets/images/shop/c3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/c3.png -------------------------------------------------------------------------------- /assets/images/shop/cart_empty.json: -------------------------------------------------------------------------------- 1 | {"v":"4.8.0","meta":{"g":"LottieFiles AE 1.1.0","a":"","k":"","d":"","tc":""},"fr":29.9700012207031,"ip":0,"op":77.0000031362743,"w":1000,"h":1000,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[480,506,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[41,-30],[34,-78],[-36.607,20.098],[40,-43],[-71,185],[26,-28]],"o":[[0,0],[-30.454,22.283],[-34,78],[51,-28],[-61.995,66.645],[70.57,-183.88],[-26,28]],"v":[[-142,44],[-139,140],[-352,106],[-171,308],[-204,227],[-313,168],[-413,67]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"d":[{"n":"d","nm":"dash","v":{"a":0,"k":30,"ix":1}},{"n":"g","nm":"gap","v":{"a":0,"k":1369,"ix":2}},{"n":"o","nm":"offset","v":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":32,"s":[103]},{"t":70.0000028511585,"s":[-1303]}],"ix":7}}],"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22.0000008960784,"op":1810.00007372281,"st":12.00000048877,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[500,500,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[41,-30],[34,-78],[-36.607,20.098],[40,-43],[-71,185],[26,-28]],"o":[[0,0],[-30.454,22.283],[-34,78],[51,-28],[-61.995,66.645],[70.57,-183.88],[-26,28]],"v":[[-142,44],[-139,140],[-352,106],[-171,308],[-204,227],[-313,168],[-413,67]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"d":[{"n":"d","nm":"dash","v":{"a":0,"k":12,"ix":1}},{"n":"g","nm":"gap","v":{"a":0,"k":1369,"ix":2}},{"n":"o","nm":"offset","v":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":20,"s":[103]},{"t":58.0000023623884,"s":[-1303]}],"ix":7}}],"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22.0000008960784,"op":1798.00007323404,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"head/boxgirl2 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":9,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[-5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":50,"s":[-5]},{"t":75.0000030548126,"s":[0]}],"ix":10},"p":{"a":0,"k":[504.173,279.4,0],"ix":2},"a":{"a":0,"k":[615.874,302.163,0],"ix":1},"s":{"a":0,"k":[83,83,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.203,0],[0,0],[0.188,-0.112],[0.266,-0.265],[0.11,-0.275],[-0.203,0],[0,0],[-0.188,0.113],[-0.266,0.266],[-0.11,0.274]],"o":[[0,0],[-0.231,0],[-0.322,0.194],[-0.206,0.206],[-0.041,0.103],[0,0],[0.232,0],[0.322,-0.194],[0.206,-0.205],[0.041,-0.104]],"v":[[3.115,-1.01],[-1.033,-1.01],[-1.711,-0.745],[-2.621,-0.032],[-3.193,0.682],[-3.115,1.01],[1.032,1.01],[1.711,0.745],[2.621,0.031],[3.193,-0.682]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[592.024,140.01],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.441,0],[0,0],[0.377,-0.376],[-0.441,0],[0,0],[-0.377,0.376]],"o":[[0,0],[-0.571,0],[-0.086,0.085],[0,0],[0.572,0],[0.085,-0.085]],"v":[[4.643,-1.01],[-2.561,-1.01],[-4.149,-0.032],[-4.643,1.01],[2.56,1.01],[4.149,0.032]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[589.932,134.862],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.203,0],[0,0],[0.187,-0.112],[0.266,-0.265],[0.109,-0.275],[-0.203,0],[0,0],[-0.188,0.113],[-0.266,0.265],[-0.11,0.274]],"o":[[0,0],[-0.232,0],[-0.323,0.194],[-0.206,0.206],[-0.042,0.103],[0,0],[0.232,0],[0.322,-0.193],[0.206,-0.206],[0.041,-0.104]],"v":[[2.569,-1.01],[-0.487,-1.01],[-1.165,-0.745],[-2.076,-0.032],[-2.647,0.682],[-2.57,1.01],[0.486,1.01],[1.165,0.745],[2.075,0.032],[2.647,-0.682]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[594.189,130.405],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.697,0.13],[1.381,-1.402],[-1.277,-1.162],[-0.539,-2.933],[1.291,0.371],[0.599,1.294],[-0.397,-0.857],[-2.347,3.604],[1.566,1.335],[1.014,0.42],[0.075,0.558],[-0.756,-0.141]],"o":[[-1.872,-0.349],[-1.032,1.047],[1.762,1.602],[0.338,1.839],[-1.421,-0.409],[-0.212,-0.458],[1.982,4.281],[1.124,-1.727],[-0.848,-0.723],[-0.383,-0.158],[-0.118,-0.875],[0.82,0.152]],"v":[[2.104,-7.117],[-2.682,-5.892],[-3.188,-2.149],[2.92,2.141],[-0.213,3.831],[-3.175,1.063],[-5.296,3.185],[4.569,3.198],[3.753,-1.848],[0.801,-3.374],[-1.262,-4.469],[0.261,-4.868]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[602.895,136.398],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-5.784,2.336]],"o":[[0,0],[0,0]],"v":[[-6.716,-0.848],[6.716,-1.168]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.6509803921568628,0.6,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[605.021,201.209],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":3,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-5.784,2.336]],"o":[[0,0],[0,0]],"v":[[-6.716,-2.008],[6.716,-0.328]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.6509803921568628,0.6,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[582.244,200.369],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.901,0.241],[8.078,-4.259],[-3.323,-5.913],[-6.748,-0.677],[-6.62,1.477],[0,0]],"o":[[-0.963,-0.223],[-21.25,-5.699],[-6,3.163],[3.324,5.912],[6.748,0.678],[0,0],[0,0]],"v":[[22.043,0.722],[19.248,0.025],[-14.734,-11.997],[-18.914,5.764],[-1.981,15.578],[22.237,12.775],[19.248,0.025]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.6509803921568628,0.6,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[543.515,174.404],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":3,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-27.722,-3.24],[2.66,-27.783],[19.547,5.242],[8.078,-4.258],[-3.324,-5.912],[-6.748,-0.677],[-6.62,1.476],[0,0]],"o":[[0,0],[3.818,-27.648],[27.722,3.24],[-63.214,18.371],[-21.25,-5.699],[-6,3.163],[3.323,5.912],[6.748,0.678],[0,0],[0,0]],"v":[[-72.745,16.895],[-29.706,4.359],[30.081,-41.908],[77.588,16.899],[-38.763,28.917],[-72.745,16.895],[-76.924,34.656],[-59.992,44.47],[-35.774,41.668],[-38.763,28.917]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.050980392156862744,0.7764705882352941,0.7215686274509804,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[601.526,145.512],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":3,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.734,-12.941],[-15.624,-0.096],[-3.417,15.247]],"o":[[2.734,12.941],[3.23,15.288],[15.625,0.095],[0,0]],"v":[[-36.33,-25.893],[-31.201,-1.615],[2.397,25.799],[36.33,-1.201]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[602.33,214.252],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[6.091,-7.297]],"o":[[-0.924,12.992],[0,0]],"v":[[5.451,-19.487],[-5.451,19.487]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[594.411,259.908],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[1.404,-13.995],[-7.319,-22.945],[-22.358,-8.953],[-13.565,19.901],[22.678,8.11],[-0.689,25.725],[5.686,1.105]],"o":[[7.301,7.834],[-2.405,23.964],[7.32,22.944],[22.358,8.953],[13.565,-19.9],[-24.231,-8.665],[0.155,-5.79],[-5.686,-1.106]],"v":[[-67.624,-74.46],[-60.836,-50.411],[-55.453,11.567],[-9.899,64.62],[54.789,47.744],[37.918,-12.56],[2.322,-69.611],[-7.677,-82.077]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34,"s":[{"i":[[0,0],[1.404,-13.995],[-7.319,-22.945],[-22.358,-8.953],[-13.565,19.901],[22.678,8.11],[-0.689,25.725],[5.686,1.105]],"o":[[7.301,7.834],[-2.405,23.964],[7.32,22.944],[22.358,8.953],[13.565,-19.9],[-24.231,-8.665],[0.155,-5.79],[-5.686,-1.106]],"v":[[-67.624,-74.46],[-60.836,-50.411],[-56.182,21.178],[-10.628,74.23],[54.06,57.355],[37.189,-2.949],[2.322,-69.611],[-7.677,-82.077]],"c":true}]},{"t":74.0000030140818,"s":[{"i":[[0,0],[1.404,-13.995],[-7.319,-22.945],[-22.358,-8.953],[-13.565,19.901],[22.678,8.11],[-0.689,25.725],[5.686,1.105]],"o":[[7.301,7.834],[-2.405,23.964],[7.32,22.944],[22.358,8.953],[13.565,-19.9],[-24.231,-8.665],[0.155,-5.79],[-5.686,-1.106]],"v":[[-67.624,-74.46],[-60.836,-50.411],[-55.453,11.567],[-9.899,64.62],[54.789,47.744],[37.918,-12.56],[2.322,-69.611],[-7.677,-82.077]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.35294117647058826,0.37254901960784315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[692.302,244.019],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":3,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1798.00007323404,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"arms/boxgirl2 Outlines","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[-18]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":13.824,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":21,"s":[-18]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":27,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":37,"s":[-18]},{"t":54.0000021994651,"s":[-18]}],"ix":10},"p":{"a":0,"k":[506.439,444.242,0],"ix":2},"a":{"a":0,"k":[534.439,398.222,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-3.407],[3.407,0],[0,3.407],[-3.407,0]],"o":[[0,3.407],[-3.407,0],[0,-3.407],[3.407,0]],"v":[[6.169,0],[0,6.169],[-6.168,0],[0,-6.169]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[632.081,461.246],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":7,"s":[{"i":[[0,0],[-22.517,-0.724],[-10.788,37.86]],"o":[[25.288,-7.398],[36.098,3.218],[0,0]],"v":[[-38.207,26.791],[38.078,30.823],[87.513,-6.807]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":14,"s":[{"i":[[0,0],[-22.888,-13.053],[-2.749,18.008]],"o":[[25.288,-7.398],[-17.303,-28.448],[0,0]],"v":[[-38.207,26.791],[38.207,35.761],[21.086,-17.93]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":21,"s":[{"i":[[0,0],[-22.517,-0.724],[-10.788,37.86]],"o":[[25.288,-7.398],[36.098,3.218],[0,0]],"v":[[-38.207,26.791],[38.078,30.823],[87.513,-6.807]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":27.176,"s":[{"i":[[0,0],[-22.888,-13.053],[-2.749,18.008]],"o":[[25.288,-7.398],[-17.303,-28.448],[0,0]],"v":[[-38.207,26.791],[38.207,35.761],[21.086,-17.93]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":37,"s":[{"i":[[0,0],[-22.517,-0.724],[-10.788,37.86]],"o":[[25.288,-7.398],[36.098,3.218],[0,0]],"v":[[-38.207,26.791],[38.078,30.823],[87.513,-6.807]],"c":false}]},{"t":54.0000021994651,"s":[{"i":[[0,0],[-22.517,-0.724],[-10.788,37.86]],"o":[[25.288,-7.398],[36.098,3.218],[0,0]],"v":[[-38.207,26.791],[38.078,30.823],[87.513,-6.807]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[636.453,358.075],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.991,-1.935],[1.393,-9.397],[3.254,-8.925],[-1.049,-10.002],[0,0],[-11.042,-10.598],[20.008,35.512]],"o":[[3.543,-0.536],[7.976,5.16],[-1.392,9.397],[-3.253,8.925],[0,0],[0.418,10.558],[7.218,-35.73],[0,0]],"v":[[-34.042,-55.116],[-23.763,-53.142],[-14.661,-27.77],[-23.79,-0.843],[-27.997,28.159],[-28.105,26.975],[6.752,55.652],[14.035,-54.499]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.050980392156862744,0.7764705882352941,0.7215686274509804,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[635.71,439.352],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-19.251,-20.715],[19.252,-11.749],[12.525,20.715],[-9.779,13.975]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":3,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40784313725490196,0.9529411764705882,0.9098039215686274,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[617.497,415.331],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0.037,-6.22],[4.993,-23.691],[-34.033,29.139],[0,0]],"o":[[0,0],[0,0],[-4.999,-3.701],[0,0],[-3.982,18.892],[0,0],[0,0]],"v":[[55.805,-7.473],[11.559,-17.777],[-4.366,-29.569],[-16.488,-23.507],[-52.904,-14.08],[1.026,8.632],[56.886,25.512]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.796078431372549,1,0.984313725490196,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[554.414,404.877],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":3,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-7.976,-5.16],[1.393,-9.397],[3.254,-8.925],[-1.049,-10.001],[2.982,11.029]],"o":[[0.571,-9.482],[7.975,5.161],[-1.393,9.396],[-3.254,8.925],[-2.982,-11.029],[0,0]],"v":[[-16.19,-29.242],[5.695,-38.07],[14.797,-12.698],[5.668,14.229],[1.461,43.23],[-8.484,4.143]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.6509803921568628,0.6,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[606.252,424.28],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":7,"s":[{"i":[[0,0],[76.287,8.852],[17.248,1.993]],"o":[[77.45,65.728],[-17.247,-2.001],[0,0]],"v":[[63.279,-99.083],[-7.091,82.071],[-65.557,72.343]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":14,"s":[{"i":[[0,0],[84.904,4.88],[17.248,1.993]],"o":[[83.039,26.063],[-17.334,-0.997],[0,0]],"v":[[-26.996,-99.139],[-19.347,87.726],[-65.557,72.343]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":21,"s":[{"i":[[0,0],[76.287,8.852],[17.248,1.993]],"o":[[77.45,65.728],[-17.247,-2.001],[0,0]],"v":[[63.279,-99.083],[-7.091,82.071],[-65.557,72.343]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":27,"s":[{"i":[[0,0],[84.904,4.88],[17.248,1.993]],"o":[[88.231,6.819],[-17.334,-0.997],[0,0]],"v":[[-46.273,-107.574],[-19.347,87.726],[-65.557,72.343]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":37,"s":[{"i":[[0,0],[76.287,8.852],[17.248,1.993]],"o":[[77.45,65.728],[-17.247,-2.001],[0,0]],"v":[[63.279,-99.083],[-7.091,82.071],[-65.557,72.343]],"c":false}]},{"t":54.0000021994651,"s":[{"i":[[0,0],[76.287,8.852],[17.248,1.993]],"o":[[77.45,65.728],[-17.247,-2.001],[0,0]],"v":[[63.279,-99.083],[-7.091,82.071],[-65.557,72.343]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.050980392156862744,0.7764705882352941,0.7215686274509804,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[717.313,386.909],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":3,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1798.00007323404,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"BOX/boxgirl2 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":7,"s":[-11]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14.961,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":21.216,"s":[-11]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":26.903,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":36.569,"s":[-11]},{"t":76.0000030955435,"s":[-11]}],"ix":10},"p":{"s":true,"x":{"a":0,"k":497.232,"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.525],"y":[0.999]},"o":{"x":[0.167],"y":[0.012]},"t":7,"s":[534.782]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.714],"y":[-0.001]},"t":14.961,"s":[473.393]},{"i":{"x":[0.086],"y":[1.001]},"o":{"x":[0.333],"y":[0]},"t":20.648,"s":[554.791]},{"i":{"x":[0.345],"y":[1.257]},"o":{"x":[0.475],"y":[0.001]},"t":26.903,"s":[484.088]},{"i":{"x":[0.058],"y":[8.039]},"o":{"x":[0.207],"y":[-15.641]},"t":37.138,"s":[534.782]},{"t":76.0000030955435,"s":[534.782]}],"ix":4}},"a":{"a":0,"k":[572.5,586.5,0],"ix":1},"s":{"a":0,"k":[83,83,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[4.345,-40.918],[0,0],[0,0],[0,0]],"o":[[0,0],[5.794,-40.405],[0,0],[0,0]],"v":[[2.264,43.63],[-8.285,42.896],[-2.262,-43.63],[8.286,-42.896]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[307.842,426.297],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[5.221,1.428]],"o":[[0,0],[0,0]],"v":[[0.841,-83.44],[-2.611,82.013]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[306.142,427.058],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-69.992,1.014]],"o":[[69.993,-1.014],[0,0]],"v":[[-112.026,3.123],[112.026,-3.123]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[477.19,351.902],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-38.969,-5.99],[1.82,-62.867]],"o":[[41.66,9.085],[-1.821,62.868],[0,0]],"v":[[-56.581,-95.724],[56.581,-72.475],[52.313,95.724]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.866666726505,0.737254901961,0.549019607843,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[308.254,427.051],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-43.799,3.2],[-73.661,-9.244],[-9.976,-73.578],[68.598,2.806],[42.988,11.764],[6.219,42.049]],"o":[[64.703,16],[-14.075,53.761],[-67.608,11.939],[-42.988,-11.764],[7.574,-63.979],[43.799,-3.2]],"v":[[-15.044,-99.102],[169.981,-81.65],[161.058,90.364],[-59.207,94.101],[-169.981,65.062],[-167.562,-99.102]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.866666726505,0.737254901961,0.549019607843,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[419.236,430.43],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":3,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[4.29,-26.25],[54.595,20.476],[-5.348,26.556]],"o":[[-5.881,28.24],[-48.63,-17.126],[7.005,-28.32],[0,0]],"v":[[81.443,-11.521],[72.476,56.222],[-39.877,9.497],[-29.331,-40.56]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":17.235,"s":[{"i":[[0,0],[4.29,-26.25],[54.595,20.475],[-5.348,26.556]],"o":[[-5.881,28.24],[-48.63,-17.126],[7.005,-28.32],[0,0]],"v":[[81.443,-11.521],[72.476,56.222],[-39.877,9.497],[-29.331,-40.56]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[18.337,-0.432],[53.327,11.084],[-23.981,4.669]],"o":[[-25.774,-4.099],[-48.63,-17.126],[24.904,-3.29],[0,0]],"v":[[81.443,-11.521],[31.961,-12.457],[-76.764,-40.908],[-29.331,-40.56]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":22.921,"s":[{"i":[[0,0],[4.29,-26.25],[54.595,20.476],[-5.348,26.556]],"o":[[-5.881,28.24],[-48.63,-17.126],[7.005,-28.32],[0,0]],"v":[[81.443,-11.521],[72.476,56.222],[-39.877,9.497],[-29.331,-40.56]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":28.608,"s":[{"i":[[0,0],[4.29,-26.25],[54.595,20.476],[-5.348,26.556]],"o":[[-5.881,28.24],[-48.63,-17.126],[7.005,-28.32],[0,0]],"v":[[81.443,-11.521],[72.476,56.222],[-39.877,9.497],[-29.331,-40.56]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":31,"s":[{"i":[[0,0],[18.337,-0.432],[53.327,11.084],[-23.981,4.669]],"o":[[-25.774,-4.099],[-48.63,-17.126],[24.904,-3.29],[0,0]],"v":[[81.443,-11.521],[31.961,-12.457],[-76.764,-40.909],[-29.331,-40.56]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":46,"s":[{"i":[[0,0],[4.29,-26.25],[54.595,20.476],[-5.348,26.556]],"o":[[-5.881,28.24],[-48.63,-17.126],[7.005,-28.32],[0,0]],"v":[[81.443,-11.521],[72.476,56.222],[-39.877,9.497],[-29.331,-40.56]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[{"i":[[0,0],[5.295,-25.538],[54.595,20.476],[-5.348,26.556]],"o":[[-5.881,28.24],[-48.63,-17.126],[7.005,-28.32],[0,0]],"v":[[81.443,-11.521],[68.394,55.122],[-39.877,9.497],[-29.331,-40.56]],"c":false}]},{"t":77.0000031362743,"s":[{"i":[[0,0],[4.29,-26.25],[54.595,20.476],[-5.348,26.556]],"o":[[-5.881,28.24],[-48.63,-17.126],[7.005,-28.32],[0,0]],"v":[[81.443,-11.521],[72.476,56.222],[-39.877,9.497],[-29.331,-40.56]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.866666726505,0.737254901961,0.549019607843,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[278.586,536.051],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[-3.518,-24.757],[85.647,-5.976],[4.373,25.634]],"o":[[1.938,21.197],[-80.626,8.376],[-2.305,-27.236],[0,0]],"v":[[96.352,-34.341],[106.656,24.809],[-115.038,40.968],[-118.704,-27.565]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[{"i":[[0,0],[-7.408,-22.677],[85.647,-5.975],[4.373,25.634]],"o":[[1.938,21.197],[-80.626,8.376],[-2.305,-27.236],[0,0]],"v":[[96.353,-34.341],[110.216,25.436],[-110.292,41.803],[-118.704,-27.565]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":16.666,"s":[{"i":[[0,0],[-3.518,-24.757],[85.647,-5.975],[4.373,25.634]],"o":[[1.938,21.197],[-80.626,8.376],[-2.305,-27.236],[0,0]],"v":[[96.353,-34.341],[106.656,24.809],[-115.038,40.968],[-118.704,-27.565]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[-29.356,-13.941],[84.442,-5.729],[19.387,14.399]],"o":[[13.559,13.713],[-83.638,8.019],[-32.035,-13.191],[0,0]],"v":[[96.353,-34.341],[136.329,-10.87],[-68.498,3.481],[-118.704,-27.565]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":22.921,"s":[{"i":[[0,0],[-3.518,-24.757],[85.647,-5.976],[4.373,25.634]],"o":[[1.938,21.197],[-80.626,8.376],[-2.305,-27.236],[0,0]],"v":[[96.352,-34.341],[106.656,24.809],[-115.038,40.968],[-118.704,-27.565]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":28.608,"s":[{"i":[[0,0],[-3.518,-24.757],[85.647,-5.976],[4.373,25.634]],"o":[[1.938,21.197],[-80.626,8.376],[-2.305,-27.236],[0,0]],"v":[[96.352,-34.341],[106.656,24.809],[-115.038,40.968],[-118.704,-27.565]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":31,"s":[{"i":[[0,0],[-29.356,-13.941],[84.442,-5.729],[19.387,14.399]],"o":[[13.559,13.713],[-83.638,8.019],[-32.035,-13.191],[0,0]],"v":[[96.353,-34.341],[136.329,-10.87],[-68.498,3.481],[-118.704,-27.565]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":46,"s":[{"i":[[0,0],[-3.518,-24.757],[85.647,-5.976],[4.373,25.634]],"o":[[1.938,21.197],[-80.626,8.376],[-2.305,-27.236],[0,0]],"v":[[96.352,-34.341],[106.656,24.809],[-115.038,40.968],[-118.704,-27.565]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":52,"s":[{"i":[[0,0],[4.341,-23.172],[85.647,-5.976],[-5.305,25.866]],"o":[[-4.364,20.108],[-80.626,8.376],[3.168,-26.192],[0,0]],"v":[[96.352,-34.341],[83.496,23.989],[-128.163,39.03],[-118.704,-27.565]],"c":false}]},{"t":77.0000031362743,"s":[{"i":[[0,0],[-3.518,-24.757],[85.647,-5.976],[4.373,25.634]],"o":[[1.938,21.197],[-80.626,8.376],[-2.305,-27.236],[0,0]],"v":[[96.352,-34.341],[106.656,24.809],[-115.038,40.968],[-118.704,-27.565]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.866666726505,0.737254901961,0.549019607843,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[483.54,552.116],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":3,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1798.00007323404,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Legs/boxgirl2 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[477.232,513.782,0],"ix":2},"a":{"a":0,"k":[572.5,586.5,0],"ix":1},"s":{"a":0,"k":[83,83,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-0.742,-7.41],[-14.493,-3.584],[-25.452,2.565]],"o":[[-5.443,5.57],[2.029,20.261],[13.455,3.327],[0,0]],"v":[[-48.474,-30.191],[-57.779,-10.254],[-0.625,23.639],[58.521,27.626]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.796078431372549,1,0.984313725490196,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[647.342,989.901],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-8.064,5.222]],"o":[[0,0],[0,0]],"v":[[-11.624,-6.953],[11.624,1.731]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.796078431372549,1,0.984313725490196,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[618.704,1014.636],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,3.45],[0,0],[0,0],[0,0],[0,0],[3.45,0]],"o":[[-3.45,0],[0,0],[0,0],[0,0],[0,0],[0,3.45],[0,0]],"v":[[-66.997,10.39],[-73.244,4.143],[-73.244,-10.39],[-70.416,-10.39],[73.244,-10.39],[73.244,4.143],[66.997,10.39]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.796078431372549,1,0.984313725490196,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[630.328,1057.988],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0.745,2.543],[-7.412,2.56],[0,0],[0,0]],"o":[[0,0],[0,0],[-2.561,-2.245],[-2.206,-7.525],[0,0],[0,0],[0,0]],"v":[[74.419,-1.574],[75.315,23.542],[-68.346,23.542],[-73.109,16.217],[-63.465,-1.762],[-21.177,-16.372],[-11.369,-23.542]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.796078431372549,1,0.984313725490196,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[628.258,1024.055],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.406,-7.312],[-14.756,-2.265],[-25.117,4.846]],"o":[[0,20.776],[3.845,19.996],[13.701,2.102],[0,0]],"v":[[-30.309,-32.271],[-58.915,0.168],[1.056,28.779],[60.321,27.425]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[561.487,975.205],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-7.561,5.927]],"o":[[0,0],[0,0]],"v":[[-11.967,-6.242],[11.968,0.315]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[519.21,1005.327],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-3.437,0.31]],"o":[[0,0],[0,0],[0,0],[0.311,3.436],[0,0]],"v":[[74.051,5],[71.843,-16.903],[-74.051,-3.715],[-72.448,10.933],[-65.663,16.593]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[535.094,1047.055],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[1.577,12.468],[-1.576,-12.468]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[605.36,1017.685],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[-2.874,-7.296],[-2.753,-2.005]],"o":[[0,0],[0,0],[-7.151,3.218],[0.971,2.467],[0,0]],"v":[[30.393,-26.012],[21.269,-17.987],[-19.532,0.37],[-27.519,19.143],[-22.114,26.012]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[485.974,1017.073],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10.98,"s":[{"i":[[0,0],[-3.442,-105.571]],"o":[[-18.704,112.217],[0,0]],"v":[[-9.493,-158.357],[9.494,158.357]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14.393,"s":[{"i":[[0,0],[-3.442,-105.571]],"o":[[3.442,105.571],[0,0]],"v":[[-9.493,-158.357],[9.494,158.357]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20.648,"s":[{"i":[[0,0],[-3.442,-105.571]],"o":[[-18.704,112.217],[0,0]],"v":[[-9.493,-158.357],[9.494,158.357]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":25.765,"s":[{"i":[[0,0],[-3.442,-105.571]],"o":[[3.442,105.571],[0,0]],"v":[[-9.493,-158.357],[9.494,158.357]],"c":false}]},{"t":32.588751327367,"s":[{"i":[[0,0],[-3.442,-105.571]],"o":[[-18.704,112.217],[0,0]],"v":[[-9.493,-158.357],[9.494,158.357]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[519.695,753.384],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10.98,"s":[{"i":[[0,0],[3.081,-104.652]],"o":[[-11.201,108.609],[0,0]],"v":[[2.06,-160.308],[6.06,160.309]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14.393,"s":[{"i":[[0,0],[3.081,-104.652]],"o":[[5.242,106.157],[0,0]],"v":[[2.06,-160.308],[6.06,160.309]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20.648,"s":[{"i":[[0,0],[3.081,-104.652]],"o":[[-11.201,108.609],[0,0]],"v":[[2.06,-160.308],[6.06,160.309]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":25.765,"s":[{"i":[[0,0],[3.081,-104.652]],"o":[[5.242,106.156],[0,0]],"v":[[2.06,-160.308],[6.06,160.309]],"c":false}]},{"t":32.588751327367,"s":[{"i":[[0,0],[3.081,-104.652]],"o":[[-11.201,108.609],[0,0]],"v":[[2.06,-160.308],[6.06,160.309]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[591.424,810.794],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":2,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10.98,"s":[{"i":[[0,0],[-21.928,-106.278]],"o":[[-33.777,91.486],[0,0]],"v":[[12.646,-187.238],[21.131,187.238]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14.393,"s":[{"i":[[0,0],[-10.66,-108.482]],"o":[[-4.585,92.5],[0,0]],"v":[[12.646,-187.238],[21.131,187.238]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20.648,"s":[{"i":[[0,0],[-21.928,-106.278]],"o":[[-33.777,91.486],[0,0]],"v":[[12.646,-187.238],[21.131,187.238]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":25.765,"s":[{"i":[[0,0],[-10.66,-108.482]],"o":[[-4.585,92.5],[0,0]],"v":[[12.646,-187.238],[21.131,187.238]],"c":false}]},{"t":32.588751327367,"s":[{"i":[[0,0],[-21.928,-106.278]],"o":[[-33.777,91.486],[0,0]],"v":[[12.646,-187.238],[21.131,187.238]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[685.846,756.199],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":2,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1798.00007323404,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Body/boxgirl2 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10.98,"s":[477.232,513.782,0],"to":[0,-1.167,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14.393,"s":[477.232,506.782,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20.648,"s":[477.232,513.782,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":25.765,"s":[477.232,506.782,0],"to":[0,0,0],"ti":[0,-1.167,0]},{"t":32.588751327367,"s":[477.232,513.782,0]}],"ix":2},"a":{"a":0,"k":[572.5,586.5,0],"ix":1},"s":{"a":0,"k":[83,83,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[0,0],[-1.842,-18.593],[20.162,4.991],[50.908,0.473],[-108.373,217.759],[-16.355,0],[0,0],[0,0],[-16.432,-8.614]],"o":[[6.366,18.406],[2.049,20.67],[-36.237,-8.969],[0,0],[10.336,-20.768],[0,0],[0,0],[18.522,-12.748],[0,0]],"v":[[132.53,-11.826],[161.147,106.417],[106.529,126.902],[-0.019,112.697],[-47.61,-79.325],[-1.019,-144.415],[23.696,-102.197],[71.999,-130.707],[125.265,-134.421]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[-1.842,-18.593],[20.162,4.991],[50.908,0.473],[-104.743,241.812],[-16.355,0],[0,0],[0,0],[-16.432,-8.614]],"o":[[6.366,18.406],[2.049,20.67],[-36.237,-8.969],[0,0],[9.221,-21.286],[0,0],[0,0],[18.522,-12.748],[0,0]],"v":[[132.53,-11.826],[161.147,106.417],[106.529,126.902],[-0.019,112.697],[-75.32,-116.675],[-1.019,-144.415],[23.696,-102.197],[71.999,-130.707],[125.265,-134.421]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[-1.842,-18.593],[20.162,4.991],[50.908,0.473],[-108.373,217.759],[-16.355,0],[0,0],[0,0],[-16.432,-8.614]],"o":[[6.366,18.406],[2.049,20.67],[-36.237,-8.969],[0,0],[10.336,-20.768],[0,0],[0,0],[18.522,-12.748],[0,0]],"v":[[132.53,-11.826],[161.147,106.417],[106.529,126.902],[-0.019,112.697],[-47.61,-88.964],[-1.019,-144.415],[23.696,-102.197],[71.999,-130.707],[125.265,-134.421]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":26,"s":[{"i":[[0,0],[-1.842,-18.593],[20.162,4.991],[50.908,0.473],[-108.373,217.759],[-16.355,0],[0,0],[0,0],[-16.432,-8.614]],"o":[[6.366,18.406],[2.049,20.67],[-36.237,-8.969],[0,0],[10.336,-20.768],[0,0],[0,0],[18.522,-12.748],[0,0]],"v":[[132.53,-11.826],[161.147,106.417],[106.529,126.902],[-0.019,112.697],[-63.272,-105.831],[-1.019,-144.415],[23.696,-102.197],[71.999,-130.707],[125.265,-134.421]],"c":false}]},{"t":33.0000013441176,"s":[{"i":[[0,0],[-1.842,-18.593],[20.162,4.991],[50.908,0.473],[-108.373,217.759],[-16.355,0],[0,0],[0,0],[-16.432,-8.614]],"o":[[6.366,18.406],[2.049,20.67],[-36.237,-8.969],[0,0],[10.336,-20.768],[0,0],[0,0],[18.522,-12.748],[0,0]],"v":[[132.53,-11.826],[161.147,106.417],[106.529,126.902],[-0.019,112.697],[-47.61,-79.325],[-1.019,-144.415],[23.696,-102.197],[71.999,-130.707],[125.265,-134.421]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.050980392156862744,0.7764705882352941,0.7215686274509804,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[559.529,428.725],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1798.00007323404,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Layer 8/boxgirl2 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[477.232,513.782,0],"ix":2},"a":{"a":0,"k":[572.5,586.5,0],"ix":1},"s":{"a":0,"k":[83,83,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[47.878,-14.752],[3.234,-71.293],[-5.895,-75.093],[33.038,-81.93],[-85.728,-107.22],[-68.517,107.681],[-69.828,139.983],[-38.029,115.117],[46.807,57.257],[162.699,89.342]],"o":[[-55.539,17.112],[-3.198,70.52],[6.233,79.398],[-49.442,122.608],[99.596,124.565],[62.205,-97.761],[57.996,-116.263],[25.413,-76.926],[-71.866,-87.91],[-72.635,-39.886]],"v":[[-164.114,-536.141],[-273.101,-369.18],[-225.408,-209.28],[-297.757,-3.278],[-280.381,426.328],[113.978,424.615],[140.88,74.349],[340.696,-142.095],[303.58,-375.651],[-19.035,-471.694]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.796078431372549,1,0.984313725490196,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[655.005,614.237],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1798.00007323404,"st":0,"bm":0}],"markers":[]} -------------------------------------------------------------------------------- /assets/images/shop/css3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/css3.png -------------------------------------------------------------------------------- /assets/images/shop/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/icon.png -------------------------------------------------------------------------------- /assets/images/shop/kid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/kid.png -------------------------------------------------------------------------------- /assets/images/shop/man.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/man.png -------------------------------------------------------------------------------- /assets/images/shop/n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/n.png -------------------------------------------------------------------------------- /assets/images/shop/pet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/pet.png -------------------------------------------------------------------------------- /assets/images/shop/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/splash.png -------------------------------------------------------------------------------- /assets/images/shop/t1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/t1.png -------------------------------------------------------------------------------- /assets/images/shop/t2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/t2.png -------------------------------------------------------------------------------- /assets/images/shop/t3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/t3.png -------------------------------------------------------------------------------- /assets/images/shop/t4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/t4.png -------------------------------------------------------------------------------- /assets/images/shop/teen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/teen.png -------------------------------------------------------------------------------- /assets/images/shop/w1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/w1.png -------------------------------------------------------------------------------- /assets/images/shop/w2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/w2.png -------------------------------------------------------------------------------- /assets/images/shop/w3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/w3.png -------------------------------------------------------------------------------- /assets/images/shop/w4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/w4.png -------------------------------------------------------------------------------- /assets/images/shop/w5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/w5.png -------------------------------------------------------------------------------- /assets/images/shop/woman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/shop/woman.png -------------------------------------------------------------------------------- /assets/images/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/assets/images/splash.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | return { 4 | presets: ["babel-preset-expo"], 5 | plugins: ["react-native-reanimated/plugin"], 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /components/Collapsible.tsx: -------------------------------------------------------------------------------- 1 | import Ionicons from '@expo/vector-icons/Ionicons'; 2 | import { PropsWithChildren, useState } from 'react'; 3 | import { StyleSheet, TouchableOpacity, useColorScheme } from 'react-native'; 4 | 5 | import { ThemedText } from '@/components/ThemedText'; 6 | import { ThemedView } from '@/components/ThemedView'; 7 | import { Colors } from '@/constants/Colors'; 8 | 9 | export function Collapsible({ children, title }: PropsWithChildren & { title: string }) { 10 | const [isOpen, setIsOpen] = useState(false); 11 | const theme = useColorScheme() ?? 'light'; 12 | 13 | return ( 14 | <ThemedView> 15 | <TouchableOpacity 16 | style={styles.heading} 17 | onPress={() => setIsOpen((value) => !value)} 18 | activeOpacity={0.8}> 19 | <Ionicons 20 | name={isOpen ? 'chevron-down' : 'chevron-forward-outline'} 21 | size={18} 22 | color={theme === 'light' ? Colors.light.icon : Colors.dark.icon} 23 | /> 24 | <ThemedText type="defaultSemiBold">{title}</ThemedText> 25 | </TouchableOpacity> 26 | {isOpen && <ThemedView style={styles.content}>{children}</ThemedView>} 27 | </ThemedView> 28 | ); 29 | } 30 | 31 | const styles = StyleSheet.create({ 32 | heading: { 33 | flexDirection: 'row', 34 | alignItems: 'center', 35 | gap: 6, 36 | }, 37 | content: { 38 | marginTop: 6, 39 | marginLeft: 24, 40 | }, 41 | }); 42 | -------------------------------------------------------------------------------- /components/ExternalLink.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'expo-router'; 2 | import { openBrowserAsync } from 'expo-web-browser'; 3 | import { type ComponentProps } from 'react'; 4 | import { Platform } from 'react-native'; 5 | 6 | type Props = Omit<ComponentProps<typeof Link>, 'href'> & { href: string }; 7 | 8 | export function ExternalLink({ href, ...rest }: Props) { 9 | return ( 10 | <Link 11 | target="_blank" 12 | {...rest} 13 | href={href} 14 | onPress={async (event) => { 15 | if (Platform.OS !== 'web') { 16 | // Prevent the default behavior of linking to the default browser on native. 17 | event.preventDefault(); 18 | // Open the link in an in-app browser. 19 | await openBrowserAsync(href); 20 | } 21 | }} 22 | /> 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /components/HelloWave.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | import Animated, { 3 | useSharedValue, 4 | useAnimatedStyle, 5 | withTiming, 6 | withRepeat, 7 | withSequence, 8 | } from 'react-native-reanimated'; 9 | 10 | import { ThemedText } from '@/components/ThemedText'; 11 | 12 | export function HelloWave() { 13 | const rotationAnimation = useSharedValue(0); 14 | 15 | rotationAnimation.value = withRepeat( 16 | withSequence(withTiming(25, { duration: 150 }), withTiming(0, { duration: 150 })), 17 | 4 // Run the animation 4 times 18 | ); 19 | 20 | const animatedStyle = useAnimatedStyle(() => ({ 21 | transform: [{ rotate: `${rotationAnimation.value}deg` }], 22 | })); 23 | 24 | return ( 25 | <Animated.View style={animatedStyle}> 26 | <ThemedText style={styles.text}>👋</ThemedText> 27 | </Animated.View> 28 | ); 29 | } 30 | 31 | const styles = StyleSheet.create({ 32 | text: { 33 | fontSize: 28, 34 | lineHeight: 32, 35 | marginTop: -6, 36 | }, 37 | }); 38 | -------------------------------------------------------------------------------- /components/ParallaxScrollView.tsx: -------------------------------------------------------------------------------- 1 | import type { PropsWithChildren, ReactElement } from 'react'; 2 | import { StyleSheet, useColorScheme } from 'react-native'; 3 | import Animated, { 4 | interpolate, 5 | useAnimatedRef, 6 | useAnimatedStyle, 7 | useScrollViewOffset, 8 | } from 'react-native-reanimated'; 9 | 10 | import { ThemedView } from '@/components/ThemedView'; 11 | 12 | const HEADER_HEIGHT = 250; 13 | 14 | type Props = PropsWithChildren<{ 15 | headerImage: ReactElement; 16 | headerBackgroundColor: { dark: string; light: string }; 17 | }>; 18 | 19 | export default function ParallaxScrollView({ 20 | children, 21 | headerImage, 22 | headerBackgroundColor, 23 | }: Props) { 24 | const colorScheme = useColorScheme() ?? 'light'; 25 | const scrollRef = useAnimatedRef<Animated.ScrollView>(); 26 | const scrollOffset = useScrollViewOffset(scrollRef); 27 | 28 | const headerAnimatedStyle = useAnimatedStyle(() => { 29 | return { 30 | transform: [ 31 | { 32 | translateY: interpolate( 33 | scrollOffset.value, 34 | [-HEADER_HEIGHT, 0, HEADER_HEIGHT], 35 | [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75] 36 | ), 37 | }, 38 | { 39 | scale: interpolate(scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]), 40 | }, 41 | ], 42 | }; 43 | }); 44 | 45 | return ( 46 | <ThemedView style={styles.container}> 47 | <Animated.ScrollView ref={scrollRef} scrollEventThrottle={16}> 48 | <Animated.View 49 | style={[ 50 | styles.header, 51 | { backgroundColor: headerBackgroundColor[colorScheme] }, 52 | headerAnimatedStyle, 53 | ]}> 54 | {headerImage} 55 | </Animated.View> 56 | <ThemedView style={styles.content}>{children}</ThemedView> 57 | </Animated.ScrollView> 58 | </ThemedView> 59 | ); 60 | } 61 | 62 | const styles = StyleSheet.create({ 63 | container: { 64 | flex: 1, 65 | }, 66 | header: { 67 | height: 250, 68 | overflow: 'hidden', 69 | }, 70 | content: { 71 | flex: 1, 72 | padding: 32, 73 | gap: 16, 74 | overflow: 'hidden', 75 | }, 76 | }); 77 | -------------------------------------------------------------------------------- /components/ThemedText.tsx: -------------------------------------------------------------------------------- 1 | import { Text, type TextProps, StyleSheet } from 'react-native'; 2 | 3 | import { useThemeColor } from '@/hooks/useThemeColor'; 4 | 5 | export type ThemedTextProps = TextProps & { 6 | lightColor?: string; 7 | darkColor?: string; 8 | type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link'; 9 | }; 10 | 11 | export function ThemedText({ 12 | style, 13 | lightColor, 14 | darkColor, 15 | type = 'default', 16 | ...rest 17 | }: ThemedTextProps) { 18 | const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text'); 19 | 20 | return ( 21 | <Text 22 | style={[ 23 | { color }, 24 | type === 'default' ? styles.default : undefined, 25 | type === 'title' ? styles.title : undefined, 26 | type === 'defaultSemiBold' ? styles.defaultSemiBold : undefined, 27 | type === 'subtitle' ? styles.subtitle : undefined, 28 | type === 'link' ? styles.link : undefined, 29 | style, 30 | ]} 31 | {...rest} 32 | /> 33 | ); 34 | } 35 | 36 | const styles = StyleSheet.create({ 37 | default: { 38 | fontSize: 16, 39 | lineHeight: 24, 40 | }, 41 | defaultSemiBold: { 42 | fontSize: 16, 43 | lineHeight: 24, 44 | fontWeight: '600', 45 | }, 46 | title: { 47 | fontSize: 32, 48 | fontWeight: 'bold', 49 | lineHeight: 32, 50 | }, 51 | subtitle: { 52 | fontSize: 20, 53 | fontWeight: 'bold', 54 | }, 55 | link: { 56 | lineHeight: 30, 57 | fontSize: 16, 58 | color: '#0a7ea4', 59 | }, 60 | }); 61 | -------------------------------------------------------------------------------- /components/ThemedView.tsx: -------------------------------------------------------------------------------- 1 | import { View, type ViewProps } from 'react-native'; 2 | 3 | import { useThemeColor } from '@/hooks/useThemeColor'; 4 | 5 | export type ThemedViewProps = ViewProps & { 6 | lightColor?: string; 7 | darkColor?: string; 8 | }; 9 | 10 | export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) { 11 | const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background'); 12 | 13 | return <View style={[{ backgroundColor }, style]} {...otherProps} />; 14 | } 15 | -------------------------------------------------------------------------------- /components/__tests__/ThemedText-test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import renderer from 'react-test-renderer'; 3 | 4 | import { ThemedText } from '../ThemedText'; 5 | 6 | it(`renders correctly`, () => { 7 | const tree = renderer.create(<ThemedText>Snapshot test!</ThemedText>).toJSON(); 8 | 9 | expect(tree).toMatchSnapshot(); 10 | }); 11 | -------------------------------------------------------------------------------- /components/__tests__/__snapshots__/ThemedText-test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`renders correctly 1`] = ` 4 | <Text 5 | style={ 6 | [ 7 | { 8 | "color": "#11181C", 9 | }, 10 | { 11 | "fontSize": 16, 12 | "lineHeight": 24, 13 | }, 14 | undefined, 15 | undefined, 16 | undefined, 17 | undefined, 18 | undefined, 19 | ] 20 | } 21 | > 22 | Snapshot test! 23 | </Text> 24 | `; 25 | -------------------------------------------------------------------------------- /components/navigation/TabBarIcon.tsx: -------------------------------------------------------------------------------- 1 | // You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/ 2 | 3 | import Ionicons from '@expo/vector-icons/Ionicons'; 4 | import { type IconProps } from '@expo/vector-icons/build/createIconSet'; 5 | import { type ComponentProps } from 'react'; 6 | 7 | export function TabBarIcon({ style, ...rest }: IconProps<ComponentProps<typeof Ionicons>['name']>) { 8 | return <Ionicons size={28} style={[{ marginBottom: -3 }, style]} {...rest} />; 9 | } 10 | -------------------------------------------------------------------------------- /components/shop/Cart.tsx: -------------------------------------------------------------------------------- 1 | import { View, Text, StyleSheet } from "react-native"; 2 | import Ionicons from "@expo/vector-icons/Ionicons"; 3 | import { useAppSelector } from "@/hooks/useRedux"; 4 | import { selectCount } from "@/providers/redux/cartSlice"; 5 | 6 | export default function Cart() { 7 | const count = useAppSelector(selectCount); 8 | return ( 9 | <View style={{ flexDirection: 'row' }}> 10 | <Ionicons name="cart-outline" size={24} color="black" /> 11 | <View style={styles.container}> 12 | <Text style={styles.badge}>{count}</Text> 13 | </View> 14 | </View> 15 | ); 16 | } 17 | 18 | const styles = StyleSheet.create({ 19 | container: { 20 | backgroundColor: 'red', 21 | width: 20, 22 | height: 20, 23 | borderRadius: 10, 24 | justifyContent: 'center', 25 | alignItems: 'center', 26 | marginLeft: -10, 27 | marginTop: -5, 28 | }, 29 | badge: { 30 | fontSize: 11, 31 | fontWeight: "bold", 32 | color: "#ffffff", 33 | }, 34 | }); 35 | -------------------------------------------------------------------------------- /components/shop/Category.tsx: -------------------------------------------------------------------------------- 1 | import { Pressable, Text, StyleSheet } from "react-native"; 2 | import { Image } from "expo-image"; 3 | import { API_URL } from "@/config"; 4 | 5 | const blurhash = 6 | "|rF?hV%2WCj[ayj[a|j[az_NaeWBj@ayfRayfQfQM{M|azj[azf6fQfQfQIpWXofj[ayj[j[fQayWCoeoeaya}j[ayfQa{oLj?j[WVj[ayayj[fQoff7azayj[ayj[j[ayofayayayj[fQj[ayayj[ayfjj[j[ayjuayj["; 7 | 8 | export default function Category({ 9 | id, 10 | name, 11 | image, 12 | onSelect, 13 | select, 14 | }: { 15 | id: string; 16 | name: string; 17 | image: any; 18 | onSelect: (name: string) => void; 19 | select: string; 20 | }) { 21 | return ( 22 | <Pressable style={styles.container} onPress={() => onSelect(id)}> 23 | <Image 24 | style={[styles.image, select === id && styles.select]} 25 | source={{ uri: API_URL + image }} 26 | placeholder={{ blurhash }} 27 | contentFit="cover" 28 | transition={1000} 29 | /> 30 | <Text style={styles.text}>{name}</Text> 31 | </Pressable> 32 | ); 33 | } 34 | 35 | const styles = StyleSheet.create({ 36 | container: { 37 | alignItems: "center", 38 | marginRight: 30, 39 | }, 40 | image: { 41 | width: 55, 42 | height: 55, 43 | marginBottom: 7, 44 | }, 45 | select: { 46 | borderRadius: 27, 47 | borderColor: "orange", 48 | borderWidth: 2, 49 | }, 50 | text: { 51 | fontSize: 12, 52 | fontWeight: "600", 53 | }, 54 | }); 55 | -------------------------------------------------------------------------------- /components/shop/Product.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | View, 3 | Text, 4 | ImageBackground, 5 | Pressable, 6 | StyleSheet, 7 | } from "react-native"; 8 | import React from "react"; 9 | import Ionicons from "@expo/vector-icons/Ionicons"; 10 | import { API_URL } from "@/config"; 11 | 12 | type ProductProps = { 13 | id: string; 14 | brand: string; 15 | title: string; 16 | star: number; 17 | quantity: number; 18 | price: number; 19 | discount: number; 20 | image: any; 21 | favourite: boolean; 22 | onCall: () => void; 23 | onAdd: () => void; 24 | }; 25 | 26 | export default function Product({ 27 | id, 28 | brand, 29 | title, 30 | star, 31 | quantity, 32 | price, 33 | discount, 34 | image, 35 | favourite, 36 | onCall, 37 | onAdd, 38 | }: ProductProps) { 39 | return ( 40 | <View style={styles.container}> 41 | <Pressable onPress={onCall}> 42 | <ImageBackground 43 | source={{ uri: API_URL+ image }} 44 | style={styles.imageView} 45 | imageStyle={styles.image} 46 | > 47 | <Pressable onPress={onAdd}> 48 | <View style={styles.heartContainer}> 49 | <Ionicons name={favourite ? "heart" : "heart-outline"} size={18} color="#E66F2D" /> 50 | </View> 51 | </Pressable> 52 | </ImageBackground> 53 | </Pressable> 54 | <View style={styles.brandContainer}> 55 | <Text style={styles.brand}>{brand}</Text> 56 | <Ionicons 57 | name="star" 58 | size={12} 59 | color="orange" 60 | style={{ paddingTop: 1 }} 61 | /> 62 | <Text style={styles.star}>{star}</Text> 63 | <Text style={styles.quantity}>({quantity})</Text> 64 | </View> 65 | <Text style={styles.title}> 66 | {title.length > 25 ? title.substring(0, 25) + "..." : title} 67 | </Text> 68 | <View style={styles.priceContainer}> 69 | <Text style={styles.price}>${price.toFixed(2)}</Text> 70 | <Text style={styles.discount}>${discount.toFixed(2)}</Text> 71 | </View> 72 | </View> 73 | ); 74 | } 75 | 76 | const styles = StyleSheet.create({ 77 | container: { 78 | marginRight: 17, 79 | }, 80 | imageView: { 81 | width: 200, 82 | height: 250, 83 | resizeMode: "cover", 84 | alignItems: "flex-end", 85 | }, 86 | image: { 87 | borderRadius: 5, 88 | }, 89 | heartContainer: { 90 | backgroundColor: "#00000015", 91 | width: 30, 92 | height: 30, 93 | borderRadius: 15, 94 | justifyContent: "center", 95 | alignItems: "center", 96 | marginTop: 12, 97 | marginRight: 12, 98 | }, 99 | brandContainer: { 100 | flexDirection: "row", 101 | marginTop: 10, 102 | }, 103 | brand: { 104 | color: "gray", 105 | fontWeight: "600", 106 | marginRight: 7, 107 | }, 108 | star: { 109 | marginHorizontal: 2, 110 | fontSize: 13, 111 | }, 112 | quantity: { 113 | color: "gray", 114 | fontSize: 13, 115 | }, 116 | title: { 117 | marginVertical: 7, 118 | fontSize: 15, 119 | fontWeight: '500', 120 | }, 121 | priceContainer: { 122 | flexDirection: 'row', 123 | }, 124 | price: { 125 | marginRight: 7, 126 | color: '#007618', 127 | fontSize: 15, 128 | fontWeight: '500', 129 | }, 130 | discount: { 131 | color: 'gray', 132 | textDecorationLine: 'line-through', 133 | }, 134 | }); 135 | -------------------------------------------------------------------------------- /components/shop/Title.tsx: -------------------------------------------------------------------------------- 1 | import { View, Text, Pressable, StyleSheet } from "react-native"; 2 | import React from "react"; 3 | 4 | export default function Title({ 5 | title, 6 | action, 7 | }: { 8 | title: string; 9 | action: string; 10 | }) { 11 | return ( 12 | <View style={styles.container}> 13 | <Text style={styles.category}>{title}</Text> 14 | <Pressable> 15 | <Text style={styles.action}>{action}</Text> 16 | </Pressable> 17 | </View> 18 | ); 19 | } 20 | 21 | const styles = StyleSheet.create({ 22 | container: { 23 | flexDirection: "row", 24 | justifyContent: "space-between", 25 | marginTop: 20, 26 | marginBottom: 15, 27 | marginRight: 20, 28 | }, 29 | category: { 30 | fontSize: 16, 31 | fontWeight: "500", 32 | }, 33 | action: { 34 | color: "gray", 35 | fontWeight: "500", 36 | }, 37 | }); 38 | 39 | // type titleProps = { 40 | // title: string; 41 | // action: string; 42 | // }; 43 | 44 | // const Title : React.FC<titleProps> = ({ title, action }) => ( 45 | // <View style={styles.container}> 46 | // <Text style={styles.category}>{title}</Text> 47 | // <Pressable> 48 | // <Text style={styles.action}>{action}</Text> 49 | // </Pressable> 50 | // </View> 51 | // ); 52 | 53 | // const Title : React.FC<{titlePs: titleProps}> = ({ titlePs}) => ( 54 | // <View style={styles.container}> 55 | // <Text style={styles.category}>{titlePs.title}</Text> 56 | // <Pressable> 57 | // <Text style={styles.action}>{titlePs.action}</Text> 58 | // </Pressable> 59 | // </View> 60 | // ); 61 | 62 | // export default function Title({ title, action }: titleProps) { 63 | // return ( 64 | // <View style={styles.container}> 65 | // <Text style={styles.category}>{title}</Text> 66 | // <Pressable> 67 | // <Text style={styles.action}>{action}</Text> 68 | // </Pressable> 69 | // </View> 70 | // ); 71 | // } 72 | -------------------------------------------------------------------------------- /components/shop/ViewPager.tsx: -------------------------------------------------------------------------------- 1 | import { View, Text, Dimensions, Animated, StyleSheet } from "react-native"; 2 | import React, {useEffect, useState} from "react"; 3 | import PagerView, { 4 | PagerViewOnPageScrollEventData, 5 | } from "react-native-pager-view"; 6 | 7 | import { 8 | // ScalingDot, 9 | // SlidingBorder, 10 | // ExpandingDot, 11 | SlidingDot, 12 | } from "react-native-animated-pagination-dots"; 13 | import { Image } from "expo-image"; 14 | 15 | const AnimatedPagerView = Animated.createAnimatedComponent(PagerView); 16 | import { sample } from "@/data"; 17 | 18 | const blurhash = 19 | "|rF?hV%2WCj[ayj[a|j[az_NaeWBj@ayfRayfQfQM{M|azj[azf6fQfQfQIpWXofj[ayj[j[fQayWCoeoeaya}j[ayfQa{oLj?j[WVj[ayayj[fQoff7azayj[ayj[j[ayofayayayj[fQj[ayayj[ayfjj[j[ayjuayj["; 20 | 21 | export default function ViewPager() { 22 | const { width, height } = Dimensions.get("window"); 23 | const pageRef = React.useRef<PagerView>(null); 24 | const scrollOffsetAnimatedValue = React.useRef(new Animated.Value(0)).current; 25 | const positionAnimatedValue = React.useRef(new Animated.Value(0)).current; 26 | const inputRange = [0, sample.length]; 27 | const scrollX = Animated.add( 28 | scrollOffsetAnimatedValue, 29 | positionAnimatedValue 30 | ).interpolate({ 31 | inputRange, 32 | outputRange: [0, sample.length * width], 33 | }); 34 | const [current, setCurrent] = useState(0); 35 | 36 | const onPageScroll = React.useMemo( 37 | () => 38 | Animated.event<PagerViewOnPageScrollEventData>( 39 | [ 40 | { 41 | nativeEvent: { 42 | offset: scrollOffsetAnimatedValue, 43 | position: positionAnimatedValue, 44 | }, 45 | }, 46 | ], 47 | { 48 | useNativeDriver: false, 49 | } 50 | ), 51 | // eslint-disable-next-line react-hooks/exhaustive-deps 52 | [] 53 | ); 54 | 55 | useEffect(() => { 56 | const intervalId = setInterval(() => { 57 | setCurrent((prev) => { 58 | const nextPage = (prev + 1) % sample.length; 59 | pageRef.current?.setPage(nextPage); 60 | return nextPage; 61 | }); 62 | }, 2000); 63 | return () => clearInterval(intervalId); 64 | }, []); 65 | 66 | return ( 67 | <View style={{ width: width, height: height / 3 }}> 68 | <AnimatedPagerView 69 | testID="pager-view" 70 | initialPage={0} 71 | ref={pageRef} 72 | style={{ height: height / 3 }} 73 | onPageScroll={onPageScroll} 74 | > 75 | {sample.map((item) => ( 76 | <View 77 | testID={`pager-view-data-${item.key}`} 78 | key={item.key} 79 | style={styles.imageView} 80 | > 81 | <Image 82 | source={item.image} 83 | style={styles.image} 84 | contentFit="contain" 85 | placeholder={blurhash} 86 | transition={1000} 87 | /> 88 | </View> 89 | ))} 90 | </AnimatedPagerView> 91 | <View style={styles.dotContainer}> 92 | <SlidingDot 93 | testID={"sliding-dot"} 94 | marginHorizontal={3} 95 | // containerStyle={{ top: 10 }} 96 | data={sample} 97 | //@ts-ignore 98 | scrollX={scrollX} 99 | dotSize={9} 100 | /> 101 | </View> 102 | </View> 103 | ); 104 | } 105 | 106 | const styles = StyleSheet.create({ 107 | imageView: { 108 | width: "100%", 109 | height: "100%", 110 | justifyContent: "center", 111 | alignItems: "center", 112 | backgroundColor: "#CBDDDA44", 113 | }, 114 | image: { 115 | width: "60%", 116 | height: "80%", 117 | }, 118 | dotContainer: { 119 | // position: 'relative', 120 | // top: -10, 121 | marginTop: 10, 122 | }, 123 | }); 124 | -------------------------------------------------------------------------------- /config/index.ts: -------------------------------------------------------------------------------- 1 | export const API_URL = "http://192.168.100.55:4000/"; 2 | -------------------------------------------------------------------------------- /constants/Colors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Below are the colors that are used in the app. The colors are defined in the light and dark mode. 3 | * There are many other ways to style your app. For example, [Nativewind](https://www.nativewind.dev/), [Tamagui](https://tamagui.dev/), [unistyles](https://reactnativeunistyles.vercel.app), etc. 4 | */ 5 | 6 | const tintColorLight = '#0a7ea4'; 7 | const tintColorDark = '#fff'; 8 | 9 | export const Colors = { 10 | light: { 11 | text: '#11181C', 12 | background: '#fff', 13 | tint: tintColorLight, 14 | icon: '#687076', 15 | tabIconDefault: '#687076', 16 | tabIconSelected: tintColorLight, 17 | }, 18 | dark: { 19 | text: '#ECEDEE', 20 | background: '#151718', 21 | tint: tintColorDark, 22 | icon: '#9BA1A6', 23 | tabIconDefault: '#9BA1A6', 24 | tabIconSelected: tintColorDark, 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /data/db.json: -------------------------------------------------------------------------------- 1 | { 2 | "users": [ 3 | { 4 | "id": "uuid1", 5 | "name": "David222757" 6 | }, 7 | { 8 | "id": "uuid2", 9 | "name": "Beckham5658" 10 | }, 11 | { 12 | "id": "uuid3", 13 | "name": "Jhon2025" 14 | }, 15 | { 16 | "id": "uuid4", 17 | "name": "Smith924" 18 | }, 19 | { 20 | "id": "uuid5", 21 | "name": "Phone467" 22 | } 23 | ], 24 | "requiredInfo": { 25 | "categories": [ 26 | { 27 | "id": "uuid1", 28 | "name": "Men", 29 | "image": "man.png" 30 | }, 31 | { 32 | "id": "uuid2", 33 | "name": "Women", 34 | "image": "woman.png" 35 | }, 36 | { 37 | "id": "uuid3", 38 | "name": "Teens", 39 | "image": "teen.png" 40 | }, 41 | { 42 | "id": "uuid4", 43 | "name": "Kids", 44 | "image": "kid.png" 45 | }, 46 | { 47 | "id": "uuid5", 48 | "name": "Babies", 49 | "image": "baby.png" 50 | }, 51 | { 52 | "id": "uuid6", 53 | "name": "Pets", 54 | "image": "pet.png" 55 | }, 56 | { 57 | "id": "uuid7", 58 | "name": "Women", 59 | "image": "woman.png" 60 | }, 61 | { 62 | "id": "uuid8", 63 | "name": "Men", 64 | "image": "man.png" 65 | }, 66 | { 67 | "id": "uuid9", 68 | "name": "Teens", 69 | "image": "teen.png" 70 | }, 71 | { 72 | "id": "uuid10", 73 | "name": "Kids", 74 | "image": "kid.png" 75 | }, 76 | { 77 | "id": "uuid11", 78 | "name": "Babies", 79 | "image": "baby.png" 80 | }, 81 | { 82 | "id": "uuid12", 83 | "name": "Pets", 84 | "image": "pet.png" 85 | } 86 | ], 87 | "colors": [ 88 | { 89 | "id": "uuid1", 90 | "name": "black", 91 | "bgColor": "#000000", 92 | "stock": true 93 | }, 94 | { 95 | "id": "uuid2", 96 | "name": "blue", 97 | "bgColor": "#2B4CC3", 98 | "stock": true 99 | }, 100 | { 101 | "id": "uuid3", 102 | "name": "purple", 103 | "bgColor": "#6680C2", 104 | "stock": false 105 | }, 106 | { 107 | "id": "uuid4", 108 | "name": "white", 109 | "bgColor": "#ffffff", 110 | "stock": true 111 | } 112 | ], 113 | "sizes": [ 114 | { 115 | "id": "uuid5", 116 | "name": "XS", 117 | "stock": false 118 | }, 119 | { 120 | "id": "uuid6", 121 | "name": "S", 122 | "stock": true 123 | }, 124 | { 125 | "id": "uuid7", 126 | "name": "M", 127 | "stock": true 128 | }, 129 | { 130 | "id": "uuid8", 131 | "name": "L", 132 | "stock": false 133 | }, 134 | { 135 | "id": "uuid9", 136 | "name": "XL", 137 | "stock": true 138 | }, 139 | { 140 | "id": "uuid10", 141 | "name": "XXL", 142 | "stock": true 143 | } 144 | ], 145 | "sample": [ 146 | { 147 | "key": 1, 148 | "image": "c1.png" 149 | }, 150 | { 151 | "key": 2, 152 | "image": "c2.png" 153 | }, 154 | { 155 | "key": 3, 156 | "image": "c3.png" 157 | } 158 | ] 159 | }, 160 | "products": [ 161 | { 162 | "id": "uuid1", 163 | "categories_id": "uuid1", 164 | "brand": "H&M", 165 | "title": "Oversized Fit Printed Mesh T-Shirt", 166 | "star": 4.9, 167 | "quantity": 136, 168 | "price": 295.5, 169 | "discount": 550, 170 | "image": "t1.png", 171 | "favourite": true, 172 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 173 | }, 174 | { 175 | "id": "uuid2", 176 | "categories_id": "uuid1", 177 | "brand": "H&M", 178 | "title": "Loose Fit T-Shirt", 179 | "star": 4.7, 180 | "quantity": 201, 181 | "price": 199.5, 182 | "discount": 0, 183 | "image": "t3.png", 184 | "favourite": false, 185 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 186 | }, 187 | { 188 | "id": "uuid3", 189 | "categories_id": "uuid2", 190 | "brand": "H&M", 191 | "title": "Regular Fit Linen", 192 | "star": 4.8, 193 | "quantity": 127, 194 | "price": 255, 195 | "discount": 0, 196 | "image": "t2.png", 197 | "favourite": false, 198 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 199 | }, 200 | { 201 | "id": "uuid4", 202 | "categories_id": "uuid1", 203 | "brand": "H&M", 204 | "title": "DryMove Fit", 205 | "star": 4.5, 206 | "quantity": 234, 207 | "price": 220, 208 | "discount": 0, 209 | "image": "t4.png", 210 | "favourite": false, 211 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 212 | }, 213 | { 214 | "id": "uuid5", 215 | "categories_id": "uuid2", 216 | "brand": "H&M", 217 | "title": "Oversized Fit Printed Mesh T-Shirt", 218 | "star": 4.9, 219 | "quantity": 136, 220 | "price": 295, 221 | "discount": 550, 222 | "image": "w1.png", 223 | "favourite": false, 224 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 225 | }, 226 | { 227 | "id": "uuid6", 228 | "categories_id": "uuid2", 229 | "brand": "H&M", 230 | "title": "Regular Fit Linen", 231 | "star": 4.8, 232 | "quantity": 127, 233 | "price": 255, 234 | "discount": 0, 235 | "image": "w2.png", 236 | "favourite": false, 237 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 238 | }, 239 | { 240 | "id": "uuid7", 241 | "categories_id": "uuid1", 242 | "brand": "H&M", 243 | "title": "DryMove Fit", 244 | "star": 4.5, 245 | "quantity": 234, 246 | "price": 220, 247 | "discount": 0, 248 | "image": "w4.png", 249 | "favourite": false, 250 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 251 | }, 252 | { 253 | "id": "uuid8", 254 | "categories_id": "uuid1", 255 | "brand": "H&M", 256 | "title": "Loose Fit T-Shirt", 257 | "star": 4.5, 258 | "quantity": 234, 259 | "price": 220, 260 | "discount": 0, 261 | "image": "w5.png", 262 | "favourite": false, 263 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 264 | }, 265 | { 266 | "id": "uuid9", 267 | "categories_id": "uuid2", 268 | "brand": "H&M", 269 | "title": "Oversized Fit Printed Mesh T-Shirt", 270 | "star": 4.9, 271 | "quantity": 136, 272 | "price": 295.5, 273 | "discount": 550, 274 | "image": "t1.png", 275 | "favourite": true, 276 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 277 | }, 278 | { 279 | "id": "uuid10", 280 | "categories_id": "uuid2", 281 | "brand": "H&M", 282 | "title": "Loose Fit T-Shirt", 283 | "star": 4.7, 284 | "quantity": 201, 285 | "price": 199.5, 286 | "discount": 0, 287 | "image": "t3.png", 288 | "favourite": false, 289 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 290 | }, 291 | { 292 | "id": "uuid11", 293 | "categories_id": "uuid3", 294 | "brand": "H&M", 295 | "title": "Regular Fit Linen", 296 | "star": 4.8, 297 | "quantity": 127, 298 | "price": 255, 299 | "discount": 0, 300 | "image": "t2.png", 301 | "favourite": false, 302 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 303 | }, 304 | { 305 | "id": "uuid12", 306 | "categories_id": "uuid3", 307 | "brand": "H&M", 308 | "title": "DryMove Fit", 309 | "star": 4.5, 310 | "quantity": 234, 311 | "price": 220, 312 | "discount": 0, 313 | "image": "t4.png", 314 | "favourite": false, 315 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 316 | }, 317 | { 318 | "id": "uuid13", 319 | "categories_id": "uuid4", 320 | "brand": "H&M", 321 | "title": "Oversized Fit Printed Mesh T-Shirt", 322 | "star": 4.9, 323 | "quantity": 136, 324 | "price": 295, 325 | "discount": 550, 326 | "image": "w1.png", 327 | "favourite": false, 328 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 329 | }, 330 | { 331 | "id": "uuid14", 332 | "categories_id": "uuid4", 333 | "brand": "H&M", 334 | "title": "Regular Fit Linen", 335 | "star": 4.8, 336 | "quantity": 127, 337 | "price": 255, 338 | "discount": 0, 339 | "image": "w2.png", 340 | "favourite": false, 341 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 342 | }, 343 | { 344 | "id": "uuid15", 345 | "categories_id": "uuid5", 346 | "brand": "H&M", 347 | "title": "DryMove Fit", 348 | "star": 4.5, 349 | "quantity": 234, 350 | "price": 220, 351 | "discount": 0, 352 | "image": "w4.png", 353 | "favourite": false, 354 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 355 | }, 356 | { 357 | "id": "uuid16", 358 | "categories_id": "uuid5", 359 | "brand": "H&M", 360 | "title": "Loose Fit T-Shirt", 361 | "star": 4.5, 362 | "quantity": 234, 363 | "price": 220, 364 | "discount": 0, 365 | "image": "w5.png", 366 | "favourite": false, 367 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 368 | }, 369 | { 370 | "id": "uuid17", 371 | "categories_id": "uuid6", 372 | "brand": "H&M", 373 | "title": "Regular Fit Linen", 374 | "star": 4.8, 375 | "quantity": 127, 376 | "price": 255, 377 | "discount": 0, 378 | "image": "w2.png", 379 | "favourite": false, 380 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 381 | }, 382 | { 383 | "id": "uuid18", 384 | "categories_id": "uuid6", 385 | "brand": "H&M", 386 | "title": "DryMove Fit", 387 | "star": 4.5, 388 | "quantity": 234, 389 | "price": 220, 390 | "discount": 0, 391 | "image": "w4.png", 392 | "favourite": false, 393 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 394 | }, 395 | { 396 | "id": "uuid19", 397 | "categories_id": "uuid6", 398 | "brand": "H&M", 399 | "title": "Loose Fit T-Shirt", 400 | "star": 4.5, 401 | "quantity": 234, 402 | "price": 220, 403 | "discount": 0, 404 | "image": "w5.png", 405 | "favourite": false, 406 | "description": "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist." 407 | } 408 | ] 409 | } 410 | -------------------------------------------------------------------------------- /data/index.ts: -------------------------------------------------------------------------------- 1 | const Woman = require("@/assets/images/shop/woman.png"); 2 | const Man = require("@/assets/images/shop/man.png"); 3 | const Teen = require("@/assets/images/shop/teen.png"); 4 | const Kid = require("@/assets/images/shop/kid.png"); 5 | const Baby = require("@/assets/images/shop/baby.png"); 6 | const Pet = require("@/assets/images/shop/pet.png"); 7 | 8 | const t1 = require("@/assets/images/shop/t1.png"); 9 | const t2 = require("@/assets/images/shop/t2.png"); 10 | const t3 = require("@/assets/images/shop/t3.png"); 11 | const t4 = require("@/assets/images/shop/t4.png"); 12 | 13 | const w1 = require("@/assets/images/shop/w1.png"); 14 | const w2 = require("@/assets/images/shop/w2.png"); 15 | const w3 = require("@/assets/images/shop/w3.png"); 16 | const w4 = require("@/assets/images/shop/w4.png"); 17 | const w5 = require("@/assets/images/shop/w5.png"); 18 | 19 | const c1 = require("@/assets/images/shop/c1.png"); 20 | const c2 = require("@/assets/images/shop/c2.png"); 21 | const c3 = require("@/assets/images/shop/c3.png"); 22 | 23 | export const categories = [ 24 | { id: "uuid1", name: "Men", image: Man }, 25 | { id: "uuid2", name: "Women", image: Woman }, 26 | { id: "uuid3", name: "Teens", image: Teen }, 27 | { id: "uuid4", name: "Kids", image: Kid }, 28 | { id: "uuid5", name: "Babies", image: Baby }, 29 | { id: "uuid6", name: "Pets", image: Pet }, 30 | { id: "uuid7", name: "Women", image: Woman }, 31 | { id: "uuid8", name: "Men", image: Man }, 32 | { id: "uuid9", name: "Teens", image: Teen }, 33 | { id: "uuid10", name: "Kids", image: Kid }, 34 | { id: "uuid11", name: "Babies", image: Baby }, 35 | { id: "uuid12", name: "Pets", image: Pet }, 36 | ]; 37 | 38 | export const description = 39 | "a long- or short-sleeved garment for the upper part of the body, usually lightweight and having a collar and a front opening. an undergarment of cotton, or other material, for the upper part of the body. a shirtwaist."; 40 | 41 | export const products = { 42 | Men: [ 43 | { 44 | id: 1, 45 | brand: "H&M", 46 | title: "Oversized Fit Printed Mesh T-Shirt", 47 | star: 4.9, 48 | quantity: 136, 49 | price: 295.3, 50 | discount: 550.3, 51 | image: t1, 52 | favourite: false, 53 | }, 54 | { 55 | id: 2, 56 | brand: "H&M", 57 | title: "Loose Fit T-Shirt", 58 | star: 4.7, 59 | quantity: 201, 60 | price: 199.0, 61 | discount: 0, 62 | image: t3, 63 | favourite: false, 64 | }, 65 | { 66 | id: 3, 67 | brand: "H&M", 68 | title: "Regular Fit Linen", 69 | star: 4.8, 70 | quantity: 127, 71 | price: 255.0, 72 | discount: 0, 73 | image: t2, 74 | favourite: false, 75 | }, 76 | { 77 | id: 4, 78 | brand: "H&M", 79 | title: "DryMove Fit", 80 | star: 4.5, 81 | quantity: 234, 82 | price: 220.0, 83 | discount: 0, 84 | image: t4, 85 | favourite: false, 86 | }, 87 | { 88 | id: 5, 89 | brand: "H&M", 90 | title: "Oversized Fit Printed Mesh T-Shirt", 91 | star: 4.9, 92 | quantity: 136, 93 | price: 295.0, 94 | discount: 550.0, 95 | image: w1, 96 | favourite: false, 97 | }, 98 | { 99 | id: 6, 100 | brand: "H&M", 101 | title: "Regular Fit Linen", 102 | star: 4.8, 103 | quantity: 127, 104 | price: 255.0, 105 | discount: 0, 106 | image: w2, 107 | favourite: false, 108 | }, 109 | { 110 | id: 7, 111 | brand: "H&M", 112 | title: "DryMove Fit", 113 | star: 4.5, 114 | quantity: 234, 115 | price: 220.0, 116 | discount: 0, 117 | image: w4, 118 | favourite: false, 119 | }, 120 | { 121 | id: 8, 122 | brand: "H&M", 123 | title: "Loose Fit T-Shirt", 124 | star: 4.5, 125 | quantity: 234, 126 | price: 220.0, 127 | discount: 0, 128 | image: w5, 129 | favourite: false, 130 | }, 131 | ], 132 | Women: [ 133 | { 134 | id: 5, 135 | brand: "H&M", 136 | title: "Oversized Fit Printed Mesh T-Shirt", 137 | star: 4.9, 138 | quantity: 136, 139 | price: 295.0, 140 | discount: 550.0, 141 | image: w1, 142 | favourite: false, 143 | }, 144 | { 145 | id: 6, 146 | brand: "H&M", 147 | title: "Regular Fit Linen", 148 | star: 4.8, 149 | quantity: 127, 150 | price: 255.0, 151 | discount: 0, 152 | image: w2, 153 | favourite: false, 154 | }, 155 | { 156 | id: 7, 157 | brand: "H&M", 158 | title: "DryMove Fit", 159 | star: 4.5, 160 | quantity: 234, 161 | price: 220.0, 162 | discount: 0, 163 | image: w4, 164 | favourite: false, 165 | }, 166 | { 167 | id: 8, 168 | brand: "H&M", 169 | title: "Loose Fit T-Shirt", 170 | star: 4.5, 171 | quantity: 234, 172 | price: 220.0, 173 | discount: 0, 174 | image: w5, 175 | favourite: false, 176 | }, 177 | { 178 | id: 1, 179 | brand: "H&M", 180 | title: "Oversized Fit Printed Mesh T-Shirt", 181 | star: 4.9, 182 | quantity: 136, 183 | price: 295.0, 184 | discount: 550.0, 185 | image: t1, 186 | favourite: false, 187 | }, 188 | { 189 | id: 2, 190 | brand: "H&M", 191 | title: "Regular Fit Linen", 192 | star: 4.8, 193 | quantity: 127, 194 | price: 255.0, 195 | discount: 0, 196 | image: t2, 197 | favourite: false, 198 | }, 199 | { 200 | id: 3, 201 | brand: "H&M", 202 | title: "Loose Fit T-Shirt", 203 | star: 4.7, 204 | quantity: 201, 205 | price: 199.0, 206 | discount: 440.0, 207 | image: t3, 208 | favourite: false, 209 | }, 210 | { 211 | id: 4, 212 | brand: "H&M", 213 | title: "DryMove Fit", 214 | star: 4.5, 215 | quantity: 234, 216 | price: 220.0, 217 | discount: 0, 218 | image: t4, 219 | favourite: false, 220 | }, 221 | ], 222 | Teens: [ 223 | { 224 | id: 3, 225 | brand: "H&M", 226 | title: "Regular Fit Linen", 227 | star: 4.8, 228 | quantity: 127, 229 | price: 255.0, 230 | discount: 0, 231 | image: t2, 232 | favourite: false, 233 | }, 234 | { 235 | id: 4, 236 | brand: "H&M", 237 | title: "DryMove Fit", 238 | star: 4.5, 239 | quantity: 234, 240 | price: 220.0, 241 | discount: 0, 242 | image: t4, 243 | favourite: false, 244 | }, 245 | { 246 | id: 5, 247 | brand: "H&M", 248 | title: "Oversized Fit Printed Mesh T-Shirt", 249 | star: 4.9, 250 | quantity: 136, 251 | price: 295.0, 252 | discount: 550.0, 253 | image: w1, 254 | favourite: false, 255 | }, 256 | ], 257 | Kids: [ 258 | { 259 | id: 7, 260 | brand: "H&M", 261 | title: "DryMove Fit", 262 | star: 4.5, 263 | quantity: 234, 264 | price: 220.0, 265 | discount: 0, 266 | image: w4, 267 | favourite: false, 268 | }, 269 | { 270 | id: 8, 271 | brand: "H&M", 272 | title: "Loose Fit T-Shirt", 273 | star: 4.5, 274 | quantity: 234, 275 | price: 220.0, 276 | discount: 0, 277 | image: w5, 278 | favourite: false, 279 | }, 280 | { 281 | id: 1, 282 | brand: "H&M", 283 | title: "Oversized Fit Printed Mesh T-Shirt", 284 | star: 4.9, 285 | quantity: 136, 286 | price: 295.0, 287 | discount: 550.0, 288 | image: t1, 289 | favourite: false, 290 | }, 291 | ], 292 | Babies: [ 293 | { 294 | id: 4, 295 | brand: "H&M", 296 | title: "DryMove Fit", 297 | star: 4.5, 298 | quantity: 234, 299 | price: 220.0, 300 | discount: 0, 301 | image: t4, 302 | favourite: false, 303 | }, 304 | { 305 | id: 5, 306 | brand: "H&M", 307 | title: "Oversized Fit Printed Mesh T-Shirt", 308 | star: 4.9, 309 | quantity: 136, 310 | price: 295.0, 311 | discount: 550.0, 312 | image: w1, 313 | favourite: false, 314 | }, 315 | { 316 | id: 6, 317 | brand: "H&M", 318 | title: "Regular Fit Linen", 319 | star: 4.8, 320 | quantity: 127, 321 | price: 255.0, 322 | discount: 0, 323 | image: w2, 324 | favourite: false, 325 | }, 326 | ], 327 | Pets: [ 328 | { 329 | id: 8, 330 | brand: "H&M", 331 | title: "Loose Fit T-Shirt", 332 | star: 4.5, 333 | quantity: 234, 334 | price: 220.0, 335 | discount: 0, 336 | image: w5, 337 | favourite: false, 338 | }, 339 | { 340 | id: 1, 341 | brand: "H&M", 342 | title: "Oversized Fit Printed Mesh T-Shirt", 343 | star: 4.9, 344 | quantity: 136, 345 | price: 295.0, 346 | discount: 550.0, 347 | image: t1, 348 | favourite: false, 349 | }, 350 | { 351 | id: 2, 352 | brand: "H&M", 353 | title: "Regular Fit Linen", 354 | star: 4.8, 355 | quantity: 127, 356 | price: 255.0, 357 | discount: 0, 358 | image: t2, 359 | favourite: false, 360 | }, 361 | ], 362 | }; 363 | 364 | export const sample = [ 365 | { key: 1, image: c1 }, 366 | { key: 2, image: c2 }, 367 | { key: 3, image: c3 }, 368 | ]; 369 | 370 | export const selectItems = { 371 | colors: [ 372 | { id: "uuid1", name: "black", bgColor: "#000000", stock: true }, 373 | { id: "uuid2", name: "blue", bgColor: "#2B4CC3", stock: true }, 374 | { id: "uuid3", name: "purple", bgColor: "#6680C2", stock: false }, 375 | { id: "uuid4", name: "white", bgColor: "#ffffff", stock: true }, 376 | ], 377 | sizes: [ 378 | { id: "uuid5", name: "XS", stock: false }, 379 | { id: "uuid6", name: "S", stock: true }, 380 | { id: "uuid7", name: "M", stock: true }, 381 | { id: "uuid8", name: "L", stock: false }, 382 | { id: "uuid9", name: "XL", stock: true }, 383 | { id: "uuid10", name: "XXL", stock: true }, 384 | ], 385 | }; 386 | -------------------------------------------------------------------------------- /data/shop/baby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/baby.png -------------------------------------------------------------------------------- /data/shop/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/banner.png -------------------------------------------------------------------------------- /data/shop/banner6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/banner6.png -------------------------------------------------------------------------------- /data/shop/c1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/c1.png -------------------------------------------------------------------------------- /data/shop/c2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/c2.png -------------------------------------------------------------------------------- /data/shop/c3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/c3.png -------------------------------------------------------------------------------- /data/shop/css3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/css3.png -------------------------------------------------------------------------------- /data/shop/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/icon.png -------------------------------------------------------------------------------- /data/shop/kid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/kid.png -------------------------------------------------------------------------------- /data/shop/man.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/man.png -------------------------------------------------------------------------------- /data/shop/n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/n.png -------------------------------------------------------------------------------- /data/shop/pet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/pet.png -------------------------------------------------------------------------------- /data/shop/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/splash.png -------------------------------------------------------------------------------- /data/shop/t1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/t1.png -------------------------------------------------------------------------------- /data/shop/t2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/t2.png -------------------------------------------------------------------------------- /data/shop/t3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/t3.png -------------------------------------------------------------------------------- /data/shop/t4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/t4.png -------------------------------------------------------------------------------- /data/shop/teen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/teen.png -------------------------------------------------------------------------------- /data/shop/w1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/w1.png -------------------------------------------------------------------------------- /data/shop/w2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/w2.png -------------------------------------------------------------------------------- /data/shop/w3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/w3.png -------------------------------------------------------------------------------- /data/shop/w4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/w4.png -------------------------------------------------------------------------------- /data/shop/w5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/w5.png -------------------------------------------------------------------------------- /data/shop/woman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bonekyaw/mdc-1/6ce6a089b38a16cb8ba2a79e4b2e4ee365b315c8/data/shop/woman.png -------------------------------------------------------------------------------- /hooks/useColorScheme.ts: -------------------------------------------------------------------------------- 1 | export { useColorScheme } from 'react-native'; 2 | -------------------------------------------------------------------------------- /hooks/useColorScheme.web.ts: -------------------------------------------------------------------------------- 1 | // NOTE: The default React Native styling doesn't support server rendering. 2 | // Server rendered styles should not change between the first render of the HTML 3 | // and the first render on the client. Typically, web developers will use CSS media queries 4 | // to render different styles on the client and server, these aren't directly supported in React Native 5 | // but can be achieved using a styling library like Nativewind. 6 | export function useColorScheme() { 7 | return 'light'; 8 | } 9 | -------------------------------------------------------------------------------- /hooks/useRedux.ts: -------------------------------------------------------------------------------- 1 | import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"; 2 | import { RootState, AppDispatch } from "@/providers/redux/store"; 3 | 4 | // Use throughout your app instead of plain `useDispatch` and `useSelector` 5 | export const useAppDispatch = () => useDispatch<AppDispatch>(); 6 | export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector; 7 | -------------------------------------------------------------------------------- /hooks/useStorageState.ts: -------------------------------------------------------------------------------- 1 | import * as SecureStore from "expo-secure-store"; 2 | import * as React from "react"; 3 | import { Platform } from "react-native"; 4 | 5 | type UseStateHook<T> = [[boolean, T | null], (value: T | null) => void]; 6 | 7 | function useAsyncState<T>( 8 | initialValue: [boolean, T | null] = [true, null] 9 | ): UseStateHook<T> { 10 | return React.useReducer( 11 | ( 12 | state: [boolean, T | null], 13 | action: T | null = null 14 | ): [boolean, T | null] => [false, action], 15 | initialValue 16 | ) as UseStateHook<T>; 17 | } 18 | 19 | export async function setStorageItemAsync(key: string, value: string | null) { 20 | if (Platform.OS === "web") { 21 | try { 22 | if (value === null) { 23 | localStorage.removeItem(key); 24 | } else { 25 | localStorage.setItem(key, value); 26 | } 27 | } catch (e) { 28 | console.error("Local storage is unavailable:", e); 29 | } 30 | } else { 31 | if (value == null) { 32 | await SecureStore.deleteItemAsync(key); 33 | } else { 34 | await SecureStore.setItemAsync(key, value); // Store value into secure-store 35 | } 36 | } 37 | } 38 | 39 | export function useStorageState(key: string): UseStateHook<string> { 40 | // Public 41 | const [state, setState] = useAsyncState<string>(); 42 | 43 | // Get 44 | React.useEffect(() => { 45 | if (Platform.OS === "web") { 46 | try { 47 | if (typeof localStorage !== "undefined") { 48 | setState(localStorage.getItem(key)); 49 | } 50 | } catch (e) { 51 | console.error("Local storage is unavailable:", e); 52 | } 53 | } else { 54 | SecureStore.getItemAsync(key).then((value) => { 55 | setState(value); 56 | }); 57 | } 58 | }, [key]); 59 | 60 | // Set session 61 | const setValue = React.useCallback( 62 | (value: string | null) => { 63 | setState(value); 64 | setStorageItemAsync(key, value); 65 | }, 66 | [key] 67 | ); 68 | 69 | return [state, setValue]; 70 | } 71 | -------------------------------------------------------------------------------- /hooks/useThemeColor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Learn more about light and dark modes: 3 | * https://docs.expo.dev/guides/color-schemes/ 4 | */ 5 | 6 | import { useColorScheme } from 'react-native'; 7 | 8 | import { Colors } from '@/constants/Colors'; 9 | 10 | export function useThemeColor( 11 | props: { light?: string; dark?: string }, 12 | colorName: keyof typeof Colors.light & keyof typeof Colors.dark 13 | ) { 14 | const theme = useColorScheme() ?? 'light'; 15 | const colorFromProps = props[theme]; 16 | 17 | if (colorFromProps) { 18 | return colorFromProps; 19 | } else { 20 | return Colors[theme][colorName]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mdc-rne", 3 | "main": "expo-router/entry", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "start": "expo start", 7 | "reset-project": "node ./scripts/reset-project.js", 8 | "android": "expo start --android", 9 | "ios": "expo start --ios", 10 | "web": "expo start --web", 11 | "test": "jest --watchAll", 12 | "lint": "expo lint" 13 | }, 14 | "jest": { 15 | "preset": "jest-expo" 16 | }, 17 | "dependencies": { 18 | "@expo/vector-icons": "^14.0.2", 19 | "@gorhom/bottom-sheet": "^4", 20 | "@react-native-picker/picker": "2.7.5", 21 | "@react-navigation/native": "^6.0.2", 22 | "@reduxjs/toolkit": "^2.2.7", 23 | "@shopify/flash-list": "1.6.4", 24 | "expo": "^51.0.31", 25 | "expo-constants": "~16.0.2", 26 | "expo-font": "~12.0.9", 27 | "expo-image": "~1.12.15", 28 | "expo-linking": "~6.3.1", 29 | "expo-router": "~3.5.23", 30 | "expo-secure-store": "~13.0.2", 31 | "expo-splash-screen": "~0.27.5", 32 | "expo-status-bar": "~1.12.1", 33 | "expo-system-ui": "~3.0.7", 34 | "expo-web-browser": "~13.0.3", 35 | "lottie-react-native": "6.7.0", 36 | "react": "18.2.0", 37 | "react-dom": "18.2.0", 38 | "react-hook-form": "^7.53.0", 39 | "react-native": "0.74.5", 40 | "react-native-animated-pagination-dots": "^0.1.73", 41 | "react-native-gesture-handler": "~2.16.1", 42 | "react-native-pager-view": "6.3.0", 43 | "react-native-reanimated": "~3.10.1", 44 | "react-native-root-toast": "^3.6.0", 45 | "react-native-safe-area-context": "4.10.5", 46 | "react-native-screens": "3.31.1", 47 | "react-native-web": "~0.19.10", 48 | "react-redux": "^9.1.2" 49 | }, 50 | "devDependencies": { 51 | "@babel/core": "^7.20.0", 52 | "@types/jest": "^29.5.12", 53 | "@types/react": "~18.2.45", 54 | "@types/react-test-renderer": "^18.0.7", 55 | "jest": "^29.2.1", 56 | "jest-expo": "~51.0.4", 57 | "json-server": "^1.0.0-beta.2", 58 | "react-test-renderer": "18.2.0", 59 | "typescript": "~5.3.3" 60 | }, 61 | "private": true 62 | } 63 | -------------------------------------------------------------------------------- /providers/ctx.tsx: -------------------------------------------------------------------------------- 1 | import { useContext, createContext, type PropsWithChildren } from "react"; 2 | import { useStorageState } from "@/hooks/useStorageState"; 3 | import { fetchApi } from "@/api"; 4 | import * as SecureStore from "expo-secure-store"; 5 | 6 | const AuthContext = createContext<{ 7 | signIn: ({}) => void; 8 | signOut: () => void; 9 | session?: string | null; 10 | isLoading: boolean; 11 | }>({ 12 | signIn: ({}) => null, 13 | signOut: () => null, 14 | session: null, 15 | isLoading: false, 16 | }); 17 | 18 | // This hook can be used to access the user info. 19 | export function useSession() { 20 | const value = useContext(AuthContext); 21 | if (process.env.NODE_ENV !== "production") { 22 | if (!value) { 23 | throw new Error("useSession must be wrapped in a <SessionProvider />"); 24 | } 25 | } 26 | 27 | return value; 28 | } 29 | 30 | export function SessionProvider({ children }: PropsWithChildren) { 31 | const [[isLoading, session], setSession] = useStorageState("session"); 32 | 33 | return ( 34 | <AuthContext.Provider 35 | value={{ 36 | signIn: async (formState) => { 37 | // Perform sign-in logic here 38 | console.log("Login Data ---------", formState); 39 | const response = await fetchApi(`users`); // Call Auth api 40 | if (response) { 41 | // store token and user info into secure storage or mmkv 42 | setSession("xxx"); // set session string as you like 43 | await SecureStore.setItemAsync("token", "mdc sample token"); // set Token - response.token 44 | } 45 | }, 46 | signOut: async () => { 47 | await SecureStore.deleteItemAsync("token"); 48 | setSession(null); 49 | }, 50 | session, 51 | isLoading, 52 | }} 53 | > 54 | {children} 55 | </AuthContext.Provider> 56 | ); 57 | } 58 | -------------------------------------------------------------------------------- /providers/redux/cartSlice.ts: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | type Cart = { 4 | id: number; 5 | title: string; 6 | price: number; 7 | image: any; 8 | items: [ 9 | { 10 | id: number; 11 | selectedColor: string; 12 | selectedSize: string; 13 | quantity: number; 14 | } 15 | ]; 16 | }; 17 | 18 | interface CartState { 19 | cartList: Cart[]; 20 | } 21 | 22 | const initialState: CartState = { 23 | cartList: [], 24 | }; //satisfies CounterState as CounterState; 25 | 26 | const cartSlice = createSlice({ 27 | name: "carts", 28 | initialState, 29 | reducers: { 30 | addCart: (state, action) => { 31 | const cartItem = action.payload; 32 | if (state.cartList.length > 0) { 33 | const isExistIndex = state.cartList.findIndex( 34 | (item) => item.id === cartItem.id 35 | ); 36 | if (isExistIndex > -1) { 37 | state.cartList[isExistIndex] = cartItem; 38 | } else state.cartList.push(cartItem); 39 | } else state.cartList.push(cartItem); 40 | }, 41 | updateCart: (state, action) => { 42 | const { id, itemId, quantity } = action.payload; 43 | const cartIndex = state.cartList.findIndex((item) => item.id === id); 44 | const itemIndex = state.cartList[cartIndex].items.findIndex( 45 | (item) => item.id === itemId 46 | ); 47 | state.cartList[cartIndex].items[itemIndex].quantity = quantity; 48 | }, 49 | deleteCart: (state, action) => { 50 | const { id, itemId } = action.payload; 51 | const cartIndex = state.cartList.findIndex((item) => item.id === id); 52 | if (state.cartList[cartIndex].items.length == 1) { 53 | state.cartList.splice(cartIndex, 1); 54 | } else { 55 | const itemIndex = state.cartList[cartIndex].items.findIndex( 56 | (item) => item.id === itemId 57 | ); 58 | state.cartList[cartIndex].items.splice(itemIndex, 1); 59 | } 60 | }, 61 | // Other reducers go here 62 | }, 63 | selectors: { 64 | selectCount: (carts) => { 65 | let totalQuantity = 0; 66 | if (carts.cartList.length > 0) { 67 | carts.cartList.forEach((cart: any) => { 68 | const total = cart.items.reduce( 69 | (total: any, item: any) => total + item.quantity, 70 | 0 71 | ); 72 | totalQuantity += total; 73 | }); 74 | } 75 | 76 | return totalQuantity; 77 | }, 78 | }, 79 | }); 80 | 81 | export const { addCart, updateCart, deleteCart } = cartSlice.actions; 82 | // Selectors returned by `slice.selectors` take the root state as their first argument. 83 | export const { selectCount } = cartSlice.selectors; 84 | 85 | export default cartSlice.reducer; 86 | 87 | // Selector functions allows us to select a value from the Redux root state. 88 | // Selectors can also be defined inline in the `useSelector` call 89 | // in a component, or inside the `createSlice.selectors` field. 90 | // export const selectCount = (state: RootState) => state.carts.cartList; 91 | -------------------------------------------------------------------------------- /providers/redux/productSlice.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createSlice, 3 | createAsyncThunk, 4 | createEntityAdapter, 5 | } from "@reduxjs/toolkit"; 6 | import { fetchApi } from "@/api"; 7 | import { ProductType } from "@/types"; 8 | 9 | export const fetchProducts = createAsyncThunk("products/fetchAll", async (_, { rejectWithValue }) => { 10 | const response = await fetchApi("products"); 11 | if (!response) { 12 | return rejectWithValue("Network connection failed. Please try again!"); 13 | } 14 | return response; 15 | }); 16 | 17 | export const updateFavouriteApi = createAsyncThunk("products/updateOne", async ({id, data}:{id: string, data: any}, { rejectWithValue }) => { 18 | const response = await fetchApi(`products/${id}`,"PATCH", "_", data ); // PUT 19 | if (!response) { 20 | return rejectWithValue("Network connection failed. Please try again!"); 21 | } 22 | return response; 23 | }); 24 | 25 | export const productsAdapter = createEntityAdapter<ProductType>(); 26 | 27 | const initialState = productsAdapter.getInitialState({ loading: false, error: false }); 28 | 29 | export const productSlice = createSlice({ 30 | name: "products", 31 | initialState, 32 | reducers: { 33 | // removeProduct: productsAdapter.removeOne, 34 | updateProduct: productsAdapter.updateOne, 35 | }, 36 | extraReducers: (builder) => { 37 | builder.addCase(fetchProducts.pending, (state) => { 38 | state.loading = true; 39 | state.error = false; 40 | }); 41 | builder.addCase(fetchProducts.fulfilled, (state, action) => { 42 | productsAdapter.upsertMany(state, action.payload); 43 | state.error = false; 44 | state.loading = false; 45 | }); 46 | builder.addCase(fetchProducts.rejected, (state, action) => { 47 | state.loading = false; 48 | state.error = true; 49 | }); 50 | builder.addCase(updateFavouriteApi.fulfilled, (state, action) => { 51 | productsAdapter.updateOne(state, {id: action.payload.id, changes: { favourite: action.payload.favourite }}); 52 | }); 53 | }, 54 | }); 55 | 56 | const reducer = productSlice.reducer; 57 | export default reducer; 58 | 59 | export const { updateProduct } = productSlice.actions; 60 | 61 | export const { 62 | selectById: selectProductById, 63 | selectIds: selectProductIds, 64 | selectEntities: selectProductEntities, 65 | selectAll: selectAllProducts, 66 | selectTotal: selectTotalProducts, 67 | } = productsAdapter.getSelectors((state: any) => state.products); 68 | -------------------------------------------------------------------------------- /providers/redux/query/apiSlice.ts: -------------------------------------------------------------------------------- 1 | import { createApi, fetchBaseQuery, retry } from "@reduxjs/toolkit/query/react"; 2 | import type { FetchArgs } from "@reduxjs/toolkit/query"; 3 | import { API_URL } from "@/config"; 4 | 5 | // import { RootState } from "@/providers/redux/store"; 6 | // import type { 7 | // BaseQueryFn, 8 | // FetchArgs, 9 | // FetchBaseQueryError, 10 | // } from "@reduxjs/toolkit/query"; 11 | // import { tokenReceived, loggedOut } from "./authSlice"; 12 | 13 | // const baseQuery = fetchBaseQuery({ baseUrl: API_URL }); 14 | // const baseQueryWithReauth: BaseQueryFn< 15 | // string | FetchArgs, 16 | // unknown, 17 | // FetchBaseQueryError 18 | // > = async (args, api, extraOptions) => { 19 | // let result = await baseQuery(args, api, extraOptions); 20 | // if (result.error && result.error.status === 401) { 21 | // // try to get a new token 22 | // const refreshResult = await baseQuery("/refreshToken", api, extraOptions); 23 | // if (refreshResult.data) { 24 | // // store the new token 25 | // api.dispatch(tokenReceived(refreshResult.data)); 26 | // // retry the initial query 27 | // result = await baseQuery(args, api, extraOptions); 28 | // } else { 29 | // api.dispatch(loggedOut()); 30 | // } 31 | // } 32 | // return result; 33 | // }; 34 | 35 | // maxRetries: 5 is the default, and can be omitted. Shown for documentation purposes. 36 | 37 | const staggeredBaseQuery = retry( 38 | fetchBaseQuery({ 39 | baseUrl: API_URL, 40 | // prepareHeaders: (headers, { getState }) => { 41 | // const token = (getState() as RootState).auth.token; 42 | // // If we have a token set in state, let's assume that we should be passing it. 43 | // if (token) { 44 | // headers.set("authorization", `Bearer ${token}`); 45 | // } 46 | // return headers; 47 | // }, 48 | }), 49 | { 50 | maxRetries: 5, 51 | } 52 | ); 53 | 54 | // const staggeredBaseQueryWithBailOut = retry( 55 | // async (args: string | FetchArgs, api, extraOptions) => { 56 | // const result = await fetchBaseQuery({ 57 | // baseUrl: API_URL, 58 | // })(args, api, extraOptions); 59 | 60 | // // bail out of re-tries immediately if unauthorized, 61 | // // because we know successive re-retries would be redundant 62 | // if (result.error?.status === 401) { 63 | // retry.fail(result.error); 64 | // } 65 | 66 | // console.log("Retrying.... in RTK "); 67 | 68 | // return result; 69 | // }, 70 | // { 71 | // maxRetries: 5, 72 | // } 73 | // ); 74 | 75 | export const apiSlice = createApi({ 76 | reducerPath: "api", 77 | baseQuery: staggeredBaseQuery, 78 | tagTypes: ["User"], // ["User", "Products", "Other"] 79 | endpoints: (builder) => ({}), 80 | }); 81 | -------------------------------------------------------------------------------- /providers/redux/requiredInfoSlice.ts: -------------------------------------------------------------------------------- 1 | import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; 2 | import { fetchApi } from "@/api"; 3 | import { CategoryType, Color, Size, Sample } from "@/types"; 4 | 5 | export const fetchRequiredInfo = createAsyncThunk( 6 | "requiredInfo/fetchAll", 7 | async (_, { rejectWithValue }) => { 8 | const response = await fetchApi("requiredInfo"); 9 | 10 | if (!response) { 11 | return rejectWithValue("Network connection failed. Please try again!"); 12 | } else if (response.error) { 13 | console.log("Response in createAsyncThunk", response); 14 | 15 | return rejectWithValue(response.message); 16 | } 17 | return response; 18 | } 19 | ); 20 | 21 | interface RequiredInfoState { 22 | categories: CategoryType[]; 23 | colors: Color[]; 24 | sizes: Size[]; 25 | sample: Sample[]; 26 | status: boolean; 27 | } 28 | 29 | const initialState: RequiredInfoState = { 30 | categories: [], 31 | colors: [], 32 | sizes: [], 33 | sample: [], 34 | status: false, 35 | }; 36 | 37 | const requiredInfoSlice = createSlice({ 38 | name: "requiredInfo", 39 | initialState, 40 | reducers: {}, 41 | extraReducers: (builder) => { 42 | builder.addCase(fetchRequiredInfo.pending, (state) => { 43 | state.status = true; 44 | }); 45 | builder.addCase(fetchRequiredInfo.fulfilled, (state, action) => { 46 | state.categories = action.payload.categories; 47 | state.colors = action.payload.colors; 48 | state.sizes = action.payload.sizes; 49 | state.sample = action.payload.sample; 50 | 51 | state.status = false; 52 | }); 53 | builder.addCase(fetchRequiredInfo.rejected, (state, action) => { 54 | state.status = false; 55 | // state.error = action.error 56 | }); 57 | }, 58 | }); 59 | 60 | export const {} = requiredInfoSlice.actions; 61 | 62 | export default requiredInfoSlice.reducer; 63 | -------------------------------------------------------------------------------- /providers/redux/store.ts: -------------------------------------------------------------------------------- 1 | import { 2 | configureStore, 3 | ThunkAction, 4 | Action, 5 | combineReducers, 6 | } from "@reduxjs/toolkit"; 7 | import { setupListeners } from "@reduxjs/toolkit/query"; 8 | 9 | import productReducer from "./productSlice"; 10 | import requiredInfoReducer from "./requiredInfoSlice"; 11 | import cartReducer from "./cartSlice"; 12 | import { apiSlice } from "./query/apiSlice"; 13 | 14 | export const store = configureStore({ 15 | reducer: { 16 | [apiSlice.reducerPath]: apiSlice.reducer, 17 | products: productReducer, 18 | requiredInfo: requiredInfoReducer, 19 | carts: cartReducer, 20 | }, 21 | middleware: (getDefaultMiddleware) => 22 | getDefaultMiddleware().concat(apiSlice.middleware), 23 | }); 24 | 25 | // const rootReducer = combineReducers({ 26 | // [api.reducerPath]: api.reducer, // for RTK query 27 | // users: userReducer, // for redux store 28 | // }); 29 | 30 | // export const store = configureStore({ 31 | // // reducer: rootReducer, 32 | // reducer: { 33 | // // Add the generated reducer as a specific top-level slice 34 | // [api.reducerPath]: api.reducer, 35 | // users: userReducer, 36 | // // Other reducers go here 37 | // }, 38 | // // Adding the api middleware enables caching, invalidation, polling, 39 | // // and other useful features of `rtk-query`. 40 | // middleware: (getDefaultMiddleware) => 41 | // getDefaultMiddleware().concat(api.middleware), 42 | // }); 43 | 44 | // optional, but required for refetchOnFocus/refetchOnReconnect behaviors 45 | // see `setupListeners` docs - takes an optional callback as the 2nd arg for customization 46 | setupListeners(store.dispatch); 47 | 48 | export type RootState = ReturnType<typeof store.getState>; 49 | export type AppDispatch = typeof store.dispatch; 50 | export type AppThunk<ReturnType = void> = ThunkAction< 51 | ReturnType, 52 | RootState, 53 | unknown, 54 | Action<string> 55 | >; 56 | -------------------------------------------------------------------------------- /providers/redux/userSlice.ts: -------------------------------------------------------------------------------- 1 | import { createEntityAdapter } from "@reduxjs/toolkit"; 2 | import { apiSlice } from "./query/apiSlice"; 3 | import * as SecureStore from "expo-secure-store"; 4 | 5 | type UserType = { 6 | id: string; 7 | name: string; 8 | }; 9 | 10 | let token: any; 11 | SecureStore.getItemAsync("token").then((value) => { 12 | token = value; 13 | console.log("RTK query ----------", token); 14 | }); 15 | 16 | const usersAdapter = createEntityAdapter<UserType>({ 17 | // sortComparer: (a, b) => b.date.localeCompare(a.date) 18 | }); 19 | 20 | const initialState = usersAdapter.getInitialState(); 21 | 22 | export const extendedApiSlice = apiSlice.injectEndpoints({ 23 | endpoints: (builder) => ({ 24 | getUsers: builder.query({ 25 | query: () => "users", // localhost:4000/users 26 | extraOptions: { maxRetries: 8 }, // Override 27 | transformResponse: (responseData: UserType[]) => { 28 | console.log("Fetching All users --------"); 29 | if (!Array.isArray(responseData)) { 30 | return usersAdapter.setAll(initialState, []); 31 | } 32 | // console.log("Response User --------", responseData); 33 | // const loadedUsers = responseData.map((user: UserType) => { 34 | // return user; 35 | // }); 36 | return usersAdapter.setAll(initialState, responseData); 37 | }, 38 | // providesTags: ["User"], 39 | providesTags: (result: any, error, arg) => [ 40 | { type: "User" as const, id: "LIST" }, 41 | ...result.ids.map((id: any) => ({ type: "User", id } as const)), 42 | ], 43 | }), 44 | updateUser: builder.mutation<UserType, UserType>({ 45 | query: (initialUser) => ({ 46 | url: `users/${initialUser.id}`, 47 | method: "PUT", 48 | // header: { 49 | // accept: "application/json", 50 | // Authorization: "Bearer " + token, 51 | // }, 52 | body: { 53 | ...initialUser, 54 | }, 55 | }), 56 | // invalidatesTags: ["User"], 57 | // invalidatesTags: (result: any, error, arg) => [ 58 | // { type: "User" as const, id: arg.id }, 59 | // ], 60 | async onQueryStarted({ id, name }, { dispatch, queryFulfilled }) { 61 | // `updateQueryData` requires the endpoint name and cache key arguments, 62 | // so it knows which piece of cache state to update 63 | const patchResult = dispatch( 64 | // updateQueryData takes three arguments: the name of the endpoint to update, the same cache key value used to identify the specific cached data, and a callback that updates the cached data. 65 | extendedApiSlice.util.updateQueryData( 66 | "getUsers", 67 | "getUsers", 68 | (draft) => { 69 | // The `draft` is Immer-wrapped and can be "mutated" like in createSlice 70 | const user = draft.entities[id]; 71 | if (user) user.name = name; 72 | } 73 | ) 74 | ); 75 | try { 76 | await queryFulfilled; 77 | } catch { 78 | patchResult.undo(); 79 | } 80 | }, 81 | }), 82 | }), 83 | }); 84 | 85 | export const { useGetUsersQuery, useUpdateUserMutation } = extendedApiSlice; 86 | -------------------------------------------------------------------------------- /scripts/reset-project.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * This script is used to reset the project to a blank state. 5 | * It moves the /app directory to /app-example and creates a new /app directory with an index.tsx and _layout.tsx file. 6 | * You can remove the `reset-project` script from package.json and safely delete this file after running it. 7 | */ 8 | 9 | const fs = require('fs'); 10 | const path = require('path'); 11 | 12 | const root = process.cwd(); 13 | const oldDirPath = path.join(root, 'app'); 14 | const newDirPath = path.join(root, 'app-example'); 15 | const newAppDirPath = path.join(root, 'app'); 16 | 17 | const indexContent = `import { Text, View } from "react-native"; 18 | 19 | export default function Index() { 20 | return ( 21 | <View 22 | style={{ 23 | flex: 1, 24 | justifyContent: "center", 25 | alignItems: "center", 26 | }} 27 | > 28 | <Text>Edit app/index.tsx to edit this screen.</Text> 29 | </View> 30 | ); 31 | } 32 | `; 33 | 34 | const layoutContent = `import { Stack } from "expo-router"; 35 | 36 | export default function RootLayout() { 37 | return ( 38 | <Stack> 39 | <Stack.Screen name="index" /> 40 | </Stack> 41 | ); 42 | } 43 | `; 44 | 45 | fs.rename(oldDirPath, newDirPath, (error) => { 46 | if (error) { 47 | return console.error(`Error renaming directory: ${error}`); 48 | } 49 | console.log('/app moved to /app-example.'); 50 | 51 | fs.mkdir(newAppDirPath, { recursive: true }, (error) => { 52 | if (error) { 53 | return console.error(`Error creating new app directory: ${error}`); 54 | } 55 | console.log('New /app directory created.'); 56 | 57 | const indexPath = path.join(newAppDirPath, 'index.tsx'); 58 | fs.writeFile(indexPath, indexContent, (error) => { 59 | if (error) { 60 | return console.error(`Error creating index.tsx: ${error}`); 61 | } 62 | console.log('app/index.tsx created.'); 63 | 64 | const layoutPath = path.join(newAppDirPath, '_layout.tsx'); 65 | fs.writeFile(layoutPath, layoutContent, (error) => { 66 | if (error) { 67 | return console.error(`Error creating _layout.tsx: ${error}`); 68 | } 69 | console.log('app/_layout.tsx created.'); 70 | }); 71 | }); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "expo/tsconfig.base", 3 | "compilerOptions": { 4 | "strict": true, 5 | "paths": { 6 | "@/*": [ 7 | "./*" 8 | ] 9 | } 10 | }, 11 | "include": [ 12 | "**/*.ts", 13 | "**/*.tsx", 14 | ".expo/types/**/*.ts", 15 | "expo-env.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /types/index.ts: -------------------------------------------------------------------------------- 1 | export interface ProductType { 2 | id: string; 3 | categories_id: string; 4 | brand: string; 5 | title: string; 6 | star: number; 7 | quantity: number; 8 | price: number; 9 | discount: number; 10 | image: any; 11 | favourite: boolean; 12 | description: string; 13 | } 14 | 15 | export interface CategoryType { 16 | id: string; 17 | name: string; 18 | image: string; 19 | } 20 | 21 | export interface Color { 22 | id: string; 23 | name: string; 24 | bgColor: string; 25 | stock: boolean; 26 | } 27 | 28 | export interface Size { 29 | id: string; 30 | name: string; 31 | stock: boolean; 32 | } 33 | 34 | export interface Sample { 35 | key: number; 36 | image: string; 37 | } 38 | --------------------------------------------------------------------------------