Skip to content

Commit

Permalink
hide medical guides
Browse files Browse the repository at this point in the history
Signed-off-by: Shreyans Jain <[email protected]>
  • Loading branch information
CodeWithShreyans committed Dec 20, 2024
1 parent 1199906 commit 9f4334f
Show file tree
Hide file tree
Showing 11 changed files with 2,777 additions and 36 deletions.
25 changes: 19 additions & 6 deletions apps/mobile/app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
import AsyncStorage from "@react-native-async-storage/async-storage"
import { useState } from "react"
import { View } from "react-native"
import { SafeAreaView } from "react-native-safe-area-context"
import { stringSimilarity } from "string-similarity-js"
import { GuidesView } from "~/components/guides"
import { LargeTitleHeader } from "~/components/nativewindui/LargeTitleHeader"
import { SearchInput } from "~/components/nativewindui/SearchInput"
import guideIndex from "~/guides/index.json"
import type GuideIndex from "~/guides/index.json"

export type SearchResult = {
title: string
slug: string
image: string
hidden: boolean
score: number
}

const rankSearch = (
const rankSearch = async (
text: string,
setSearchResults: React.Dispatch<React.SetStateAction<SearchResult[]>>,
guideIndex: typeof GuideIndex,
) => {
const searchResults: SearchResult[] = []
for (const v of guideIndex) {
const score = stringSimilarity(text, v.title)
if (score > 0.2) {
searchResults.push({ ...v, score: score })
if (score > 0.2 && !v.hidden) {
searchResults.push({ ...v, hidden: !!v.hidden, score: score })
}
}
searchResults.sort((a, b) => b.score - a.score)
Expand All @@ -33,6 +36,13 @@ const rankSearch = (
export default function HomeScreen() {
const [searchValue, setSearchValue] = useState("")
const [searchResults, setSearchResults] = useState<SearchResult[]>([])
const [guideIndex, setGuideIndex] = useState<typeof GuideIndex>([])

AsyncStorage.getItem("guideIndex").then((value) => {
if (value) {
setGuideIndex(JSON.parse(value))
}
})

return (
<>
Expand All @@ -53,11 +63,14 @@ export default function HomeScreen() {
defaultValue={searchValue}
onChangeText={(text) => {
setSearchValue(text)
rankSearch(text, setSearchResults)
rankSearch(text, setSearchResults, guideIndex)
}}
/>
</View>
<GuidesView searchResults={searchResults} />
<GuidesView
searchResults={searchResults}
guideIndex={guideIndex}
/>
</SafeAreaView>
</>
)
Expand Down
3 changes: 3 additions & 0 deletions apps/mobile/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default function RootLayout() {
// });

registerBackgroundFetchAsync()

;(async () => {
const baseUrl = "https://content.useguider.com"
AsyncStorage.setItem("lastFetch", new Date().toISOString())
Expand All @@ -46,6 +47,8 @@ export default function RootLayout() {

await AsyncStorage.setItem("guideIndex", JSON.stringify(newIndex))

console.log(newIndex)

for (const i of newIndex) {
const guide = await (
await fetch(`${baseUrl}/${i.slug}.json`)
Expand Down
47 changes: 26 additions & 21 deletions apps/mobile/app/guide/[slug].tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import AsyncStorage from "@react-native-async-storage/async-storage"
import { Icon } from "@roninoss/icons"
import { getNetworkStateAsync } from "expo-network"
import { Stack, useLocalSearchParams } from "expo-router"
import { useEffect, useState } from "react"
import { FlatList, ScrollView, View, useWindowDimensions } from "react-native"
import { useSafeAreaInsets } from "react-native-safe-area-context"
import YoutubePlayer, { PLAYER_STATES } from "react-native-youtube-iframe"
import { Text } from "~/components/nativewindui/Text"
import { Skeleton } from "~/components/skeleton"
import { useColorScheme } from "~/lib/useColorScheme"
import { COLORS } from "~/theme/colors"

type Guide = {
title: string
Expand All @@ -32,7 +31,7 @@ const GuidePage = () => {

const { width } = useWindowDimensions()

const { colorScheme } = useColorScheme()
const { isDarkColorScheme } = useColorScheme()

useEffect(() => {
AsyncStorage.getItem(slug as string).then((guide) => {
Expand Down Expand Up @@ -94,27 +93,33 @@ const GuidePage = () => {
}}
/>
{playerLoading ? (
<View
// <View
// style={{
// height: ((width - insets.right - 32) / 16) * 9,
// }}
// className="items-center justify-center"
// >
// <Icon
// name="arrow-up"
// ios={{
// name: "arrow.triangle.2.circlepath",
// symbolEffect: {
// type: "pulse",
// animateBy: "layer",
// speed: 1,
// isActive: true,
// },
// }}
// size={40}
// color={COLORS[colorScheme].foreground}
// />
// </View>
<Skeleton
dark={isDarkColorScheme}
style={{
height: ((width - insets.right - 32) / 16) * 9,
}}
className="items-center justify-center"
>
<Icon
name="arrow-up"
ios={{
name: "arrow.triangle.2.circlepath",
symbolEffect: {
type: "pulse",
animateBy: "layer",
speed: 1,
isActive: true,
},
}}
size={40}
color={COLORS[colorScheme].foreground}
/>
</View>
/>
) : null}
</View>
) : null}
Expand Down
17 changes: 14 additions & 3 deletions apps/mobile/components/guides.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
import { Link } from "expo-router"
import { View } from "react-native"
import type { SearchResult } from "~/app/(tabs)"
import guideIndex from "~/guides/index.json"
import type GuideIndex from "~/guides/index.json"
import { ESTIMATED_ITEM_HEIGHT, List, ListItem } from "./nativewindui/List"

const GuidesView = ({ searchResults }: { searchResults: SearchResult[] }) => {
const GuidesView = ({
searchResults,
guideIndex,
}: {
searchResults: SearchResult[]
guideIndex: typeof GuideIndex
}) => {
console.log(guideIndex)
return (
<View className="h-full w-screen">
<List
keyboardShouldPersistTaps="handled"
variant="insets"
// @ts-ignore
data={searchResults.length > 0 ? searchResults : guideIndex}
data={
searchResults.length > 0
? searchResults
: guideIndex.filter((v) => !v.hidden)
}
estimatedItemSize={ESTIMATED_ITEM_HEIGHT.titleOnly}
renderItem={(item) => (
<Link
Expand Down
124 changes: 124 additions & 0 deletions apps/mobile/components/skeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
"use client"

import React from "react"
import {
Animated,
Easing,
StyleSheet,
View,
type ViewStyle,
} from "react-native"

const BASE_COLORS = {
dark: { primary: "rgb(17, 17, 17)", secondary: "rgb(51, 51, 51)" },
light: {
primary: "rgb(250, 250, 250)",
secondary: "rgb(205, 205, 205)",
},
} as const

const makeColors = (mode: keyof typeof BASE_COLORS) => [
BASE_COLORS[mode].primary,
BASE_COLORS[mode].secondary,
BASE_COLORS[mode].secondary,
BASE_COLORS[mode].primary,
BASE_COLORS[mode].secondary,
BASE_COLORS[mode].primary,
]

const DARK_COLORS = new Array(3).fill(0).flatMap(() => makeColors("dark"))

const LIGHT_COLORS = new Array(3).fill(0).flatMap(() => makeColors("light"))

export const Skeleton = ({
style,
delay,
dark,
}: {
style?: ViewStyle
delay?: number
dark?: boolean
} = {}) => {
const translateX = React.useRef(new Animated.Value(-1)).current
const [width, setWidth] = React.useState(150)

const colors = dark ? DARK_COLORS : LIGHT_COLORS
const targetRef = React.useRef<View>(null)

const onLayout = React.useCallback(() => {
targetRef.current?.measureInWindow((_x, _y, width, _height) => {
setWidth(width)
})
}, [])

React.useEffect(() => {
Animated.loop(
Animated.sequence([
Animated.timing(translateX, {
delay: delay || 0,
toValue: 1,
duration: 5000,
useNativeDriver: process.env.EXPO_OS !== "web",
// Ease in
easing: Easing.in(Easing.ease),
}),
]),
).start()
}, [translateX])

const translateXStyle = React.useMemo(
() => ({
transform: [
{
translateX: translateX.interpolate({
inputRange: [-1, 1],
outputRange: [-width * 8, width],
}),
},
],
}),
[translateX, width],
)

return (
<View
ref={targetRef}
style={[
{
height: 32,
borderRadius: 8,
borderCurve: "continuous",
overflow: "hidden",
backgroundColor: "transparent",
},
style,
]}
onLayout={onLayout}
>
<Animated.View
style={[
translateXStyle,
{
width: "800%",
height: "100%",
backgroundColor: "transparent",
},
]}
>
<Animated.View
style={[
StyleSheet.absoluteFill,
{
[process.env.EXPO_OS === "web"
? "backgroundImage"
: "experimental_backgroundImage"]:
`linear-gradient(to right, ${colors.join(
", ",
)})`,
},
]}
/>
</Animated.View>
</View>
)
}
3 changes: 2 additions & 1 deletion apps/mobile/guides/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"title": "How To Perform CPR on a Baby",
"slug": "cpr-baby",
"image": "",
"updated": "2024-12-04"
"updated": "2024-12-04",
"hidden": true
}
]
4 changes: 2 additions & 2 deletions apps/mobile/lib/background-fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
// 2. Register the task at some point in your app by providing the same name,
// and some configuration options for how the background fetch should behave
// Note: This does NOT need to be in the global scope and CAN be used in your React components!
async function registerBackgroundFetchAsync() {
const registerBackgroundFetchAsync = async () => {
return BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
minimumInterval: 24 * 60 * 60, // 15 minutes
stopOnTerminate: false, // android only,
startOnBoot: true, // android only
});
}
};

export { registerBackgroundFetchAsync };
5 changes: 5 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
"strictCase": false
}
}
},
"correctness": {
"useExhaustiveDependencies": {
"level": "warn"
}
}
}
},
Expand Down
Loading

0 comments on commit 9f4334f

Please sign in to comment.