Sherlock / components / userPostListView.tsx
userPostListView.tsx
Raw
import React, { useContext, useEffect, useState } from "react";
import { Text, View } from '../components/Themed'; 
import {Pressable, StyleSheet, Touchable} from "react-native";
import global, { width } from "../constants/global";
import Colors from "../constants/Colors";
import { getIncidentEmoji } from "../constants/emojis";
import { TouchableOpacity } from "react-native";
import { Badge, BadgeText, Button, ButtonIcon, ButtonText, get, HStack, Icon, Menu, MenuIcon, MenuItem, MenuItemLabel, Popover, set } from "@gluestack-ui/themed";
import { Ionicons, MaterialCommunityIcons, Octicons } from "@expo/vector-icons";
import { router, useLocalSearchParams, useNavigation } from "expo-router";
import { deleteEntity, dislikeEntity, getEntityCounts, hasLiked, likeEntity, unlikeEntity } from "./backend";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { useSettings } from "./appSettingsContext";

//Loads relative time plugin
dayjs.extend(relativeTime);


type PostListViewProps = {
    post:any;
    posts:any;
}

export function formatnum(num:number){
    if(num>=1000000000){
        return (num/1000000000).toFixed(1) + "B";
    }else if(num>=1000000){
        return (num/1000000).toFixed(1) + "M";
    }else if(num>=1000){
        return (num/1000).toFixed(1) + "K";
    }else{
        return num;
    }
}

const UserPostListView = React.memo((props: PostListViewProps) => {
    const [feed, setFeed] =  useState(props.posts);
    const index = feed.findIndex((item:any) => item.eid == props.post.item.eid);
    const [menuSelected, setMenuSelected] = useState(new Set([]) as any);
    const appSettings = useSettings();

    let post = props.post.item;
    let emoji = getIncidentEmoji(post.alias, '6', true);

    useEffect(() => {
        getEntityCounts(post.eid).then((res) => {
            let t = [...feed];
            t[index].likeCount = res.likes;
            t[index].commentCount = res.comments;
            setFeed(t);

        }).catch((err) => {
            console.log("Error getting entity counts: ", err);
        })
    },[])

    return(
            <Pressable
                style={styles.container}
                onPress={()=>{
                    global.passedPost = post;
                    router.push({
                        pathname:'/(profile)/post',
                        params:{
                            posts:feed
                        }
                    })
                }}
            >

            {/* Header */}
            <View style={styles.header}>
                {/* Emoji view */}
                <View style={[styles.emojiContainer, {backgroundColor:Colors.map["class"+emoji[1] as keyof typeof Colors.map]}]}>
                    <Text adjustsFontSizeToFit numberOfLines={1} style={styles.emoji}>{emoji[0]}</Text>
                </View>

                {/* User alias with divider */}
                <View style={styles.headertitlecontainer}>
                    
                    {appSettings.settings.showOP &&<Badge
                        size="sm"
                        variant="outline"
                        backgroundColor={Colors.dark.alertBackground}
                        borderColor={Colors.dark.redPastelClicked}
                        borderRadius={5}
                        width={55}
                    >
                        <BadgeText textAlign="center" width='100%' color={Colors.dark.text}>Yours</BadgeText>
                    </Badge>}

                    <Text adjustsFontSizeToFit numberOfLines={1} style={styles.title}>{post.alias}</Text>
                    {/* <View style={[styles.separator, {marginTop:0, }]}/> */}
                </View>

                <Menu
                    placement="bottom right"
                    selectionMode="single"
                    shadowColor="transparent"
                    maxWidth={width*0.3}
                    backgroundColor={Colors.dark.background}
                    selectedKeys={menuSelected}
                    onSelectionChange={(keys) => {
                        setMenuSelected(keys)
                        //@ts-ignore
                        switch (keys.currentKey){
                            case "Report":
                                console.log("Report clicked");
                                break;
                            case "Delete":
                                deleteEntity(post.eid).then((res) => {
                                    console.log("Post deleted: ", res);
                                    let t = [...feed];
                                    t = t.filter((item: any) => item.eid != post.eid);
                                    console.log(t.length)
                                    setFeed(t);
                                }).catch((err) => {
                                    console.log("Error deleting post: ", err);
                                })
                                break;
                            default:
                                console.log("Default clicked");
                        }
                    }}
                    closeOnSelect={true}
                    trigger={({ ...triggerProps }) => {
                        return (
                        <Pressable
                            {...triggerProps}
                            style={styles.menu}
                            >
                                <MaterialCommunityIcons style={styles.menuIcon} name="dots-vertical" size={24} color={Colors.dark.text} />
                            </Pressable>
                        )
                    }}
                >
                    <MenuItem key="Delete" textValue="Delete" $active-bgColor={Colors.dark.backgroundModal} >
                        <MaterialCommunityIcons name="delete" size={24} color={Colors.dark.redBright} />
                        <MenuItemLabel size="sm" color={Colors.dark.text}>Delete</MenuItemLabel>
                    </MenuItem>
                </Menu>



            </View>
            
            {/* Main text body */}
            <View style={styles.content}>
                <Text adjustsFontSizeToFit minimumFontScale={0.6} style={styles.body}>{post.body}</Text>
            </View>

            {/* Footer */}
            <View style={styles.footer}>

                <View style={styles.time}>
                    <Text adjustsFontSizeToFit numberOfLines={1} style={[styles.footerText, styles.timetext]}>{dayjs(post.created_at).fromNow()}</Text>
                </View>

                {/* Comments */}
                <TouchableOpacity 
                    style={styles.iconcontainer}
                    activeOpacity={0.7}
                    onPress={()=>{
                        global.passedPost = post;
                        router.push({
                            pathname: '/(home)/post',
                        });
                    }}
                >
                    <MaterialCommunityIcons name="comment" size={33} color={Colors.dark.text} style={styles.commenticon} />
                    <Text adjustsFontSizeToFit numberOfLines={1} style={[styles.footerText, styles.icontext]}>{formatnum(feed[index].commentCount)}</Text>
                </TouchableOpacity>

                {/* Likes */}
                <View style={[styles.iconcontainer,{flex:1, maxWidth:'35%', marginRight:'5%', columnGap:5}]}>
                    <Ionicons name="chevron-expand-sharp" size={33} color={Colors.dark.redBright} style={styles.likeicon} />
                    <Text adjustsFontSizeToFit numberOfLines={1} minimumFontScale={0.7} style={[styles.footerText, styles.icontext, {flex:1}]}>{formatnum(feed[index].likeCount)}</Text>
                </View>

            </View>

            {/* Divider between posts */}
            <View style={[styles.separator, {alignSelf:'center', width:global.width, height:1}]} />

            </Pressable>
    )
})

const styles =StyleSheet.create({
    container:{
        flex:1,
        width: global.width,
        minHeight: global.height*0.32,
        borderColor: Colors.dark.tabBg,
        borderWidth: 2,
        flexDirection: 'column',
        alignItems: 'center',
        padding:0,
    },
    content:{
        backgroundColor: Colors.dark.tabBg,
        flexDirection: 'column',
        width:'100%',
        flex:1,
        borderRadius: 10,
        overflow: 'hidden',
        padding:1
    },
    header:{
        backgroundColor: Colors.dark.tabBg,
        flexDirection: 'row',
        width: '100%',
        alignItems: 'center',
        columnGap: 10,
        padding: 10,
        flex:1,
        borderRadius: 10,
        height: global.height*.1,
        maxHeight: global.height*.1,

    },
    menu:{
        backgroundColor: Colors.dark.tabBg,
        
    },
    menuIcon:{
        width:'100%',
    },
    title:{
        fontSize: 25,
        fontWeight: 'bold',
        color: Colors.dark.cyan,
        backgroundColor: Colors.dark.tabBg,
        textAlignVertical:'bottom',
    },
    emojiContainer:{
        justifyContent: 'center',
        alignItems: 'center',
        height: global.height*.08,
        width: global.height*.08,
        borderWidth:5,
        borderColor:Colors.dark.backgroundProfile,
        borderRadius: 10,
        alignSelf:"flex-start",
    },
    emoji:{
        fontSize: 40,
    },
    separator: {
        height: 2,
        // width: '80%',
        alignSelf: "flex-start",
        justifyContent: 'flex-start',
        marginBottom:5,
        backgroundColor: Colors.dark.darkText,
        borderRadius: 10,
        marginTop: 5,
    },
    footerdivide:{
        alignSelf: 'center',
        height:1,
        backgroundColor: Colors.dark.darkText,
    },
    headertitlecontainer:{
        flexDirection: 'column',
        rowGap: 5,
        width: global.width*0.9-global.height*.1-global.width*0.08,
        backgroundColor: Colors.dark.tabBg,
        height: global.height*.08,
        justifyContent: 'center',
    },
    body:{
        fontSize: 20,
        fontWeight: 'bold',
        color: Colors.dark.text,
        textAlign: 'center',
        backgroundColor: Colors.dark.tabBg,
        width:global.width*0.9,
        alignSelf:'center',
        marginVertical:10,
    },
    footer:{
        backgroundColor: Colors.dark.tabBg,
        width: width,
        height: global.height*0.08,
        bottom:0,
        flexDirection: 'row',
        paddingHorizontal:10,
        paddingBottom:0,
        flex:1,
        alignSelf:'center',
        justifyContent:'space-between',
    },
    footerText:{
        fontSize: 12,
        fontWeight: 'bold',
        color: Colors.dark.text,
        alignSelf:'flex-start',
        backgroundColor: Colors.dark.tabBg,
        textAlignVertical:'bottom',
    },
    time:{
        flexDirection: 'column',
        rowGap: 2,
        width: '26%',
        height: '100%',
        justifyContent: 'center',
        backgroundColor: Colors.dark.tabBg,
        borderRadius: 10,
        marginBottom: 10,
    },
    timetext:{
        textAlign:'center',
        paddingLeft: 5,
        justifyContent:'center',
        alignSelf:'center',
    },
    likeicon:{
        alignSelf:'center',
    },
    commenticon:{
        alignSelf:'center',
        transform: 'scaleX(-1)',
    },
    iconcontainer:{
        flexDirection: 'row',
        width: '26%',
        height: '100%',
        justifyContent: 'center',
        backgroundColor: Colors.dark.tabBg,
        // marginLeft: 10,
    },
    icontext:{
        fontSize: 20,
        textAlign:'center',
        alignSelf:'center',
        justifyContent:'center',
        flex:1,
    }
})

export default UserPostListView;