Sherlock / app / (tabs) / (profile) / notifications.tsx
notifications.tsx
Raw
import {View, Text} from "../../../components/Themed";
import {Linking, StyleSheet} from "react-native";
import Colors from "../../../constants/Colors";
import { useEffect, useState } from "react";
import { VStack, HStack, Switch } from "@gluestack-ui/themed";
import * as Notifications from 'expo-notifications'
import global from "../../../constants/global";
import { getSubscriptions, subscribe, deleteSubscription } from "../../../components/backend";


type NotificationKey =
    | "crime_all"
    | "crime_low"
    | "crime_medium"
    | "crime_high"
    | "social_comment"
    | "social_upvote_post"
    | "social_upvote_comment"
    | "social_downvote_post"
    | "social_downvote_comment"
    | "social_remove_post"
    | "social_remove_comment"
    ;

export default function NotificationsScreen() {
    type NotificationSettings = Record<NotificationKey, boolean>;
    const [notify, setNotify] = useState<NotificationSettings>({
        crime_all:false,
        crime_high:false,
        crime_medium:false,
        crime_low:false,
        social_comment: false,
        social_downvote_post:false,
        social_downvote_comment:false,
        social_remove_post:false,
        social_remove_comment:false,
        social_upvote_post:false,
        social_upvote_comment:false,
    })
    const [allow, setAllow] = useState(false)
    const [permissions, setPermissions] = useState<Notifications.NotificationPermissionsStatus>()
    const [all, setAll] = useState(false)

    useEffect(()=>{
        const getPerms = async ()=>{
            let status = await Notifications.getPermissionsAsync()
            setAllow(status.granted)
            setPermissions(status)
        }

        getPerms()

        getSubscriptions().then((topics)=>{
            const validNotificationKeys: Set<NotificationKey> = new Set([
                "crime_all",
                "crime_low",
                "crime_medium",
                "crime_high",
                "social_comment",
                "social_upvote_post",
                "social_upvote_comment",
                "social_downvote_post",
                "social_downvote_comment",
                "social_remove_post",
                "social_remove_comment"
            ]);

            console.log(topics)
            let newNotify = notify;

            for(const topic of topics){
                if(validNotificationKeys.has(topic.topic)){
                    if(topic.topic == 'crime_all'){
                        setAll(true)
                    }
                    newNotify[topic.topic as NotificationKey] = true
                }
            }

            setNotify({...newNotify})
        })

    },[])

    const requestNotificationPerm = async ()=>{
        let status = await Notifications.requestPermissionsAsync()

        if(!status.granted){
            setAllow(false)
        }else{
            
        }
    }


    const handleToggle = (key:NotificationKey) =>{
        const newValue = !notify[key];
        
        //Subscribes to topic in backend
        if(key == 'crime_all'){
            
            if(newValue){
                subscribe(key).then(()=>{
                    setNotify({...notify,"crime_high":false, "crime_low":false, "crime_medium":false, [key]:newValue})
                    setAll(newValue)
                }).catch((error)=>{
                    console.log(error)
                })
            }else{
                deleteSubscription(key).then(()=>{
                    setNotify({...notify,"crime_high":false, "crime_low":false, "crime_medium":false, [key]:newValue})
                    setAll(newValue);
                }).catch((error)=>{
                    console.log(error)
                })
            }
        }else{
            if(newValue){
                subscribe(key).then(()=>{
                    setNotify({ ...notify, [key]: newValue });
                }).catch((error)=>{
                    console.log(error)
                })
            }else{
                deleteSubscription(key).then(()=>{
                    setNotify({...notify, [key]:newValue})
                }).catch((error)=>{
                    console.log(error)
                })
            }

        }
    }

    return (
        <View style={styles.container}>
            <View style={styles.content}>
                {/* Notifications toggle */}
                <HStack style={[styles.setting, {paddingHorizontal:18, marginVertical:10, marginBottom:30}]}>
                    <Text style={styles.allowText}>Allow Notifications</Text>
                    <Switch
                        size="lg"
                        sx={{
                            props:{
                                trackColor:{
                                    true:Colors.dark.cyan,
                                    false:Colors.dark.text
                                }
                            }
                        }}
                        value={allow}
                        onValueChange={(value)=>{
                            setAllow(value)

                            if(value && !permissions?.canAskAgain && permissions){
                                Linking.openSettings()
                                
                            }else if(value){
                                requestNotificationPerm()
                            }else{

                                deleteSubscription([])
                                console.log("Setting device status in db")
                            }
                        }}
                    />

                </HStack>


                {/* Notification settings */}
                {allow&&<Text style={styles.title}>Crime</Text>}
                {allow&&<VStack style={styles.card}>
                    {[
                        { label: 'Notify for ALL crime reports', key: 'crime_all' },
                        { label: 'High severity crimes', key: 'crime_high' },
                        { label: 'Medium severity crimes', key: 'crime_medium' },
                        { label: 'Low severity crimes', key: 'crime_low' },
                    ].map(({ label, key }) => (
                        <HStack
                            key={key}
                            style={styles.setting}
                        >
                            <Text style={styles.optionText}>{label}</Text>
                            <Switch
                                size="md"
                                isDisabled={key!='crime_all'?all:false}
                                sx={{
                                    props:{
                                        trackColor:{
                                            true:Colors.dark.redBright,
                                            false:Colors.dark.text
                                        }
                                    }
                                    }}
                                value={notify[key as NotificationKey]}
                                onValueChange={() => handleToggle(key as NotificationKey)}
                            />
                        </HStack>
                    ))}
                </VStack>}

                
                {allow&&<Text style={styles.title}>Social</Text>}
                {allow&&<VStack style={styles.card}>
                    {[
                        { label: 'New comment on your post', key: 'social_comment' },
                        { label: 'Your post was up voted', key: 'social_upvote_post' },
                        { label: 'Your post was down voted', key: 'social_downvote_post' },
                        { label: 'Post removal [down votes]', key: 'social_remove_post' },
                        { label: 'Your comment was up voted', key: 'social_upvote_comment' },
                        { label: 'Your comment was down voted', key: 'social_downvote_comment' },
                        { label: 'Comment removal [down votes]', key: 'social_remove_comment' },

                    ].map(({ label, key }) => (
                        <HStack
                            key={key}
                            style={styles.setting}
                        >
                            <Text style={styles.optionText}>{label}</Text>
                            <Switch
                                size="md"
                                sx={{
                                    props:{
                                        trackColor:{
                                            true:Colors.dark.redBright,
                                            false:Colors.dark.text
                                        }
                                    }
                                    }}
                                value={notify[key as NotificationKey]}
                                onValueChange={() => handleToggle(key as NotificationKey)}
                            />
                        </HStack>
                    ))}
                </VStack>}
            </View>
        </View>
    )

    // return (
    //     <View style={styles.container}>
    //         <View style={styles.content}>
    //         <Text style={styles.title}>Notification Preferences</Text>

    //             <HStack justifyContent="space-between">
    //                 <Text style={styles.label}>Allow Notifications</Text>
    //                 <Switch
    //                     size="md"
    //                     value={allow}
    //                     defaultValue={allow}
    //                     onValueChange={(value)=>{
    //                         console.log('Notifications toggle: ', value)
    //                         if(value){
    //                             setAllow(true)
    //                         }else{ 
    //                             setAllow(false)
    //                         }
    //                     }}

    //                     sx={{
    //                         props:{
    //                             trackColor:{
    //                                 true:Colors.dark.redBright,
    //                                 false:Colors.dark.text
    //                             }
    //                         }
    //                         }}
    //                 />
    //             </HStack>



    //             {allow&&<VStack space="lg" mt="$4">
    //                 {[
    //                     { label: 'Notify for ALL crime reports', key: 'crime_all' },
    //                     { label: 'High severity crimes', key: 'crime_high' },
    //                     { label: 'Medium severity crimes', key: 'crime_medium' },
    //                     { label: 'Low severity crimes', key: 'crime_low' },
    //                 ].map(({ label, key }) => (
    //                     <HStack
    //                         key={key}
    //                         justifyContent="space-between"
    //                         alignItems="center"
    //                     >
    //                         <Text style={styles.label}>{label}</Text>
    //                         <Switch
    //                             size="md"
    //                             sx={{
    //                                 props:{
    //                                     trackColor:{
    //                                         true:Colors.dark.redBright,
    //                                         false:Colors.dark.text
    //                                     }
    //                                 }
    //                                 }}
    //                             value={notify[key as NotificationKey]}
    //                             onValueChange={() => handleToggle(key as NotificationKey)}
    //                         />
    //                     </HStack>
    //                 ))}
    //             </VStack>}

    //         </View>
    //     </View>
    // )
}

const styles = StyleSheet.create({
    container:{
        flex:1,
    },
    content:{
        flex:1,
        alignItems:'center',
        justifyContent:'flex-start',
        backgroundColor:Colors.dark.tabBg,
    },
    card:{
        borderRadius: 10,
        backgroundColor: Colors.dark.background,
        padding:10,
        width: global.width*0.95,
        marginBottom: 15,
        rowGap:10,
    },
    title:{
        fontSize: 24,
        fontWeight: 'bold',
        marginBottom: 5,
        color: Colors.dark.cyan,
        alignSelf:'flex-start',
        marginLeft:global.width*0.05-5
    },
    setting:{
        width:'100%',
        flexDirection:'row',
        justifyContent:'space-between'
    },
    optionText:{
        fontSize:18,
        textAlignVertical:'center',
        color:Colors.dark.text
    },
    allowText:{
        fontSize:22,
        textAlignVertical:'center',
        color:Colors.dark.redBright,
        fontWeight:'bold'
    },
    optionToggle:{
        color:Colors.dark.cyan
    },
    selection:{
        width:global.width*0.4
    }
})