upd: redesign
This commit is contained in:
@@ -1,11 +1,9 @@
|
|||||||
import AppHeader from "@/components/AppHeader";
|
import AppHeader from "@/components/AppHeader";
|
||||||
import BorderBottomItem from "@/components/borderBottomItem";
|
|
||||||
import BorderBottomItem2 from "@/components/borderBottomItem2";
|
import BorderBottomItem2 from "@/components/borderBottomItem2";
|
||||||
import HeaderRightDiscussionGeneralDetail from "@/components/discussion_general/headerDiscussionDetail";
|
import HeaderRightDiscussionGeneralDetail from "@/components/discussion_general/headerDiscussionDetail";
|
||||||
import DrawerBottom from "@/components/drawerBottom";
|
import DrawerBottom from "@/components/drawerBottom";
|
||||||
import ImageUser from "@/components/imageNew";
|
import ImageUser from "@/components/imageNew";
|
||||||
import { InputForm } from "@/components/inputForm";
|
import { InputForm } from "@/components/inputForm";
|
||||||
import LabelStatus from "@/components/labelStatus";
|
|
||||||
import MenuItemRow from "@/components/menuItemRow";
|
import MenuItemRow from "@/components/menuItemRow";
|
||||||
import ModalConfirmation from "@/components/ModalConfirmation";
|
import ModalConfirmation from "@/components/ModalConfirmation";
|
||||||
import Skeleton from "@/components/skeleton";
|
import Skeleton from "@/components/skeleton";
|
||||||
@@ -271,29 +269,36 @@ export default function DetailDiscussionGeneral() {
|
|||||||
borderType="all"
|
borderType="all"
|
||||||
bgColor="white"
|
bgColor="white"
|
||||||
icon={
|
icon={
|
||||||
<View style={[Styles.iconContent]}>
|
<View style={[Styles.discussionIconCircleLg, { backgroundColor: colors.icon + '20' }]}>
|
||||||
<MaterialIcons name="chat" size={25} color={'black'} />
|
<Feather name="message-circle" size={22} color={colors.icon} />
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
title={data?.title}
|
title={data?.title}
|
||||||
titleShowAll={true}
|
titleShowAll={true}
|
||||||
subtitle={
|
subtitle={
|
||||||
!data?.isActive ?
|
<View style={[Styles.discussionStatusPill, {
|
||||||
<LabelStatus category='warning' text='ARSIP' size="small" />
|
borderColor: !data?.isActive
|
||||||
:
|
? '#F59E0B'
|
||||||
<LabelStatus category={data.status == 1 ? 'success' : 'error'} text={data.status == 1 ? 'BUKA' : 'TUTUP'} size="small" />
|
: data?.status == 1 ? '#10B981' : colors.dimmed + '80',
|
||||||
|
}]}>
|
||||||
|
<Text style={[Styles.discussionStatusText, {
|
||||||
|
color: !data?.isActive
|
||||||
|
? '#F59E0B'
|
||||||
|
: data?.status == 1 ? '#10B981' : colors.dimmed,
|
||||||
|
}]}>
|
||||||
|
{!data?.isActive ? 'Arsip' : data?.status == 1 ? 'Buka' : 'Tutup'}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
}
|
}
|
||||||
desc={data?.desc}
|
desc={data?.desc}
|
||||||
leftBottomInfo={
|
leftBottomInfo={
|
||||||
<View style={[Styles.rowItemsCenter]}>
|
<View style={[Styles.rowItemsCenter]}>
|
||||||
<Ionicons name="chatbox-ellipses-outline" size={18} color={colors.dimmed} style={Styles.mr05} />
|
<Feather name="message-square" size={14} color={colors.dimmed} style={Styles.mr05} />
|
||||||
<Text style={[Styles.textInformation, { color: colors.dimmed }, Styles.mb05]}>{dataKomentar.length} Komentar</Text>
|
<Text style={[Styles.textInformation, { color: colors.dimmed }]}>{dataKomentar.length} Komentar</Text>
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
rightBottomInfo={
|
rightBottomInfo={
|
||||||
<View style={[Styles.rowItemsCenter]}>
|
<Text style={[Styles.textInformation, { color: colors.dimmed }]}>{data?.createdAt}</Text>
|
||||||
<Text style={[Styles.textInformation, { color: colors.dimmed }, Styles.mb05]}>{data?.createdAt}</Text>
|
|
||||||
</View>
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@@ -306,36 +311,56 @@ export default function DetailDiscussionGeneral() {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
:
|
:
|
||||||
dataKomentar.map((item, i) => {
|
dataKomentar.map((item, i) => (
|
||||||
return (
|
<Pressable
|
||||||
<BorderBottomItem
|
key={i}
|
||||||
key={i}
|
onPress={() => {
|
||||||
borderType="all"
|
setDetailMore((prev: any) =>
|
||||||
colorPress
|
prev.includes(item.id)
|
||||||
icon={
|
? prev.filter((id: string) => id !== item.id)
|
||||||
<ImageUser src={`${ConstEnv.url_storage}/files/${item.img}`} size="xs" />
|
: [...prev, item.id]
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
onLongPress={() => {
|
||||||
|
item.idUser == entities.id && data?.status != 2 && data?.isActive && handleMenuKomentar(item.id, item.comment)
|
||||||
|
}}
|
||||||
|
style={({ pressed }) => [
|
||||||
|
Styles.discussionCommentCard,
|
||||||
|
{
|
||||||
|
backgroundColor: pressed ? colors.icon + '10' : colors.card,
|
||||||
|
borderColor: colors.icon + '20',
|
||||||
}
|
}
|
||||||
title={item.username}
|
]}
|
||||||
rightTopInfo={item.createdAt}
|
>
|
||||||
desc={item.comment}
|
<View style={Styles.flex1}>
|
||||||
rightBottomInfo={item.isEdited ? "Edited" : ""}
|
{/* Name + time */}
|
||||||
descEllipsize={detailMore.includes(item.id) ? false : true}
|
<View style={[Styles.rowSpaceBetween, Styles.itemsCenter, Styles.mb05]}>
|
||||||
bgColor="white"
|
<View style={[Styles.rowItemsCenter, { gap: 8, flex: 1, marginRight: 8 }]}>
|
||||||
onPress={() => {
|
<ImageUser src={`${ConstEnv.url_storage}/files/${item.img}`} size="xs" />
|
||||||
setDetailMore((prev: any) => {
|
<Text style={[Styles.textMediumSemiBold, { color: colors.text }]} numberOfLines={1}>
|
||||||
if (prev.includes(item.id)) {
|
{item.username}
|
||||||
return prev.filter((id: string) => id !== item.id)
|
</Text>
|
||||||
} else {
|
{item.isEdited && (
|
||||||
return [...prev, item.id]
|
<Text style={[Styles.discussionEditedText, { color: colors.dimmed }]}>
|
||||||
}
|
diedit
|
||||||
})
|
</Text>
|
||||||
}}
|
)}
|
||||||
onLongPress={() => {
|
</View>
|
||||||
item.idUser == entities.id && data?.status != 2 && data?.isActive && handleMenuKomentar(item.id, item.comment)
|
<Text style={[Styles.discussionDateText, { color: colors.dimmed, flexShrink: 0 }]}>
|
||||||
}}
|
{item.createdAt}
|
||||||
/>
|
</Text>
|
||||||
)
|
</View>
|
||||||
})
|
|
||||||
|
{/* Comment text */}
|
||||||
|
<Text
|
||||||
|
style={[Styles.textDefault, { color: colors.text }]}
|
||||||
|
numberOfLines={detailMore.includes(item.id) ? 0 : 3}
|
||||||
|
>
|
||||||
|
{item.comment}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</Pressable>
|
||||||
|
))
|
||||||
}
|
}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@@ -372,15 +397,14 @@ export default function DetailDiscussionGeneral() {
|
|||||||
multiline
|
multiline
|
||||||
focus={viewEdit}
|
focus={viewEdit}
|
||||||
itemRight={
|
itemRight={
|
||||||
<Pressable onPress={() => {
|
<Pressable
|
||||||
(!loadingSendKomentar && selectKomentar.comment != '' && !regexOnlySpacesOrEnter.test(selectKomentar.comment) && data?.status === 1 && data?.isActive && (memberDiscussion || (entityUser.role != "user" && entityUser.role != "coadmin")))
|
onPress={() => {
|
||||||
&& handleEditKomentar()
|
(!loadingSendKomentar && selectKomentar.comment != '' && !regexOnlySpacesOrEnter.test(selectKomentar.comment) && data?.status === 1 && data?.isActive && (memberDiscussion || (entityUser.role != "user" && entityUser.role != "coadmin")))
|
||||||
}}
|
&& handleEditKomentar()
|
||||||
style={[
|
}}
|
||||||
Platform.OS == 'android' && Styles.mb12,
|
style={[Platform.OS == 'android' && Styles.mb12]}
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
<MaterialIcons name="send" size={25} style={(loadingSendKomentar || selectKomentar.comment == '' || regexOnlySpacesOrEnter.test(selectKomentar.comment) || data?.status === 2 || !data?.isActive || (!memberDiscussion && (entityUser.role == "user" || entityUser.role == "coadmin"))) ? { color: colors.dimmed } : { color: colors.tint }} />
|
<MaterialIcons name="send" size={25} style={(loadingSendKomentar || selectKomentar.comment == '' || regexOnlySpacesOrEnter.test(selectKomentar.comment) || data?.status === 2 || !data?.isActive || (!memberDiscussion && (entityUser.role == "user" || entityUser.role == "coadmin"))) ? { color: colors.dimmed } : { color: colors.tint }} />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -398,15 +422,14 @@ export default function DetailDiscussionGeneral() {
|
|||||||
multiline
|
multiline
|
||||||
focus={viewEdit}
|
focus={viewEdit}
|
||||||
itemRight={
|
itemRight={
|
||||||
<Pressable onPress={() => {
|
<Pressable
|
||||||
(!loadingSendKomentar && komentar != '' && !regexOnlySpacesOrEnter.test(komentar) && data?.status === 1 && data?.isActive && (memberDiscussion || (entityUser.role != "user" && entityUser.role != "coadmin")))
|
onPress={() => {
|
||||||
&& handleKomentar()
|
(!loadingSendKomentar && komentar != '' && !regexOnlySpacesOrEnter.test(komentar) && data?.status === 1 && data?.isActive && (memberDiscussion || (entityUser.role != "user" && entityUser.role != "coadmin")))
|
||||||
}}
|
&& handleKomentar()
|
||||||
style={[
|
}}
|
||||||
Platform.OS == 'android' && Styles.mb12,
|
style={[Platform.OS == 'android' && Styles.mb12]}
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
<MaterialIcons name="send" size={25} style={(loadingSendKomentar || komentar == '' || regexOnlySpacesOrEnter.test(komentar) || data?.status === 2 || !data?.isActive || (!memberDiscussion && (entityUser.role == "user" || entityUser.role == "coadmin"))) ? { color: colors.dimmed } : { color: colors.tint }} />
|
<MaterialIcons name="send" size={25} style={(loadingSendKomentar || komentar == '' || regexOnlySpacesOrEnter.test(komentar) || data?.status === 2 || !data?.isActive || (!memberDiscussion && (entityUser.role == "user" || entityUser.role == "coadmin"))) ? { color: colors.dimmed } : { color: colors.tint }} />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,23 +1,20 @@
|
|||||||
import BorderBottomItem from "@/components/borderBottomItem";
|
|
||||||
import ButtonTab from "@/components/buttonTab";
|
import ButtonTab from "@/components/buttonTab";
|
||||||
import InputSearch from "@/components/inputSearch";
|
import InputSearch from "@/components/inputSearch";
|
||||||
import LabelStatus from "@/components/labelStatus";
|
import LabelStatus from "@/components/labelStatus";
|
||||||
import SkeletonContent from "@/components/skeletonContent";
|
import SkeletonContent from "@/components/skeletonContent";
|
||||||
import Text from "@/components/Text";
|
import Text from "@/components/Text";
|
||||||
import WrapTab from "@/components/wrapTab";
|
import WrapTab from "@/components/wrapTab";
|
||||||
import { ColorsStatus } from "@/constants/ColorsStatus";
|
|
||||||
import Styles from "@/constants/Styles";
|
import Styles from "@/constants/Styles";
|
||||||
import { apiGetDiscussionGeneral } from "@/lib/api";
|
import { apiGetDiscussionGeneral } from "@/lib/api";
|
||||||
import { useAuthSession } from "@/providers/AuthProvider";
|
import { useAuthSession } from "@/providers/AuthProvider";
|
||||||
import { useTheme } from "@/providers/ThemeProvider";
|
import { useTheme } from "@/providers/ThemeProvider";
|
||||||
import { AntDesign, Feather, Ionicons, MaterialIcons } from "@expo/vector-icons";
|
import { AntDesign, Feather } from "@expo/vector-icons";
|
||||||
import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query";
|
import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { router, useLocalSearchParams } from "expo-router";
|
import { router, useLocalSearchParams } from "expo-router";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { RefreshControl, View, VirtualizedList } from "react-native";
|
import { FlatList, Pressable, RefreshControl, View } from "react-native";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string
|
id: string
|
||||||
title: string
|
title: string
|
||||||
@@ -38,7 +35,6 @@ export default function Discussion() {
|
|||||||
const [status, setStatus] = useState<'true' | 'false'>(active == 'false' ? 'false' : 'true')
|
const [status, setStatus] = useState<'true' | 'false'>(active == 'false' ? 'false' : 'true')
|
||||||
const [refreshing, setRefreshing] = useState(false)
|
const [refreshing, setRefreshing] = useState(false)
|
||||||
|
|
||||||
// TanStack Query for Discussions with Infinite Scroll
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
fetchNextPage,
|
fetchNextPage,
|
||||||
@@ -50,12 +46,12 @@ export default function Discussion() {
|
|||||||
queryKey: ['discussions', { status, search, group }],
|
queryKey: ['discussions', { status, search, group }],
|
||||||
queryFn: async ({ pageParam = 1 }) => {
|
queryFn: async ({ pageParam = 1 }) => {
|
||||||
const hasil = await decryptToken(String(token?.current))
|
const hasil = await decryptToken(String(token?.current))
|
||||||
const response = await apiGetDiscussionGeneral({
|
const response = await apiGetDiscussionGeneral({
|
||||||
user: hasil,
|
user: hasil,
|
||||||
active: status,
|
active: status,
|
||||||
search: search,
|
search: search,
|
||||||
group: String(group),
|
group: String(group),
|
||||||
page: pageParam
|
page: pageParam
|
||||||
})
|
})
|
||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
@@ -67,17 +63,14 @@ export default function Discussion() {
|
|||||||
staleTime: 0,
|
staleTime: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Flatten pages into a single data array
|
|
||||||
const flatData = useMemo(() => {
|
const flatData = useMemo(() => {
|
||||||
return data?.pages.flatMap(page => page.data) || [];
|
return data?.pages.flatMap(page => page.data) || [];
|
||||||
}, [data])
|
}, [data])
|
||||||
|
|
||||||
// Get nameGroup from the first available page
|
|
||||||
const nameGroup = useMemo(() => {
|
const nameGroup = useMemo(() => {
|
||||||
return data?.pages[0]?.filter?.name || "";
|
return data?.pages[0]?.filter?.name || "";
|
||||||
}, [data])
|
}, [data])
|
||||||
|
|
||||||
// Refetch when manual update state changes
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
refetch()
|
refetch()
|
||||||
}, [update, refetch])
|
}, [update, refetch])
|
||||||
@@ -88,113 +81,129 @@ export default function Discussion() {
|
|||||||
setRefreshing(false)
|
setRefreshing(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadMoreData = () => {
|
const isOpen = (item: Props) => item.status === 1
|
||||||
if (hasNextPage && !isFetchingNextPage) {
|
|
||||||
fetchNextPage()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const arrSkeleton = [0, 1, 2, 3, 4]
|
|
||||||
|
|
||||||
const getItem = (_data: unknown, index: number): Props => ({
|
|
||||||
id: flatData[index]?.id,
|
|
||||||
title: flatData[index]?.title,
|
|
||||||
desc: flatData[index]?.desc,
|
|
||||||
status: flatData[index]?.status,
|
|
||||||
total_komentar: flatData[index]?.total_komentar,
|
|
||||||
createdAt: flatData[index]?.createdAt,
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[Styles.p15, Styles.flex1, { backgroundColor: colors.background }]}>
|
<View style={[Styles.flex1, { backgroundColor: colors.background }]}>
|
||||||
<View>
|
{/* Header controls */}
|
||||||
{
|
<View style={[Styles.ph15, { paddingTop: 12 }]}>
|
||||||
entityUser.role != "user" && entityUser.role != "coadmin" &&
|
{entityUser.role != "user" && entityUser.role != "coadmin" && (
|
||||||
<WrapTab>
|
<WrapTab>
|
||||||
<ButtonTab
|
<ButtonTab
|
||||||
active={status == "false" ? "false" : "true"}
|
active={status == "false" ? "false" : "true"}
|
||||||
value="true"
|
value="true"
|
||||||
onPress={() => { setStatus("true") }}
|
onPress={() => setStatus("true")}
|
||||||
label="Aktif"
|
label="Aktif"
|
||||||
icon={<Feather name="check-circle" color={status == "false" ? colors.dimmed : 'white'} size={20} />}
|
icon={<Feather name="check-circle" color={status == "false" ? colors.dimmed : 'white'} size={20} />}
|
||||||
n={2} />
|
n={2}
|
||||||
|
/>
|
||||||
<ButtonTab
|
<ButtonTab
|
||||||
active={status == "false" ? "false" : "true"}
|
active={status == "false" ? "false" : "true"}
|
||||||
value="false"
|
value="false"
|
||||||
onPress={() => { setStatus("false") }}
|
onPress={() => setStatus("false")}
|
||||||
label="Arsip"
|
label="Arsip"
|
||||||
icon={<AntDesign name="closecircleo" color={status == "true" ? colors.dimmed : 'white'} size={20} />}
|
icon={<AntDesign name="closecircleo" color={status == "true" ? colors.dimmed : 'white'} size={20} />}
|
||||||
n={2} />
|
n={2}
|
||||||
|
/>
|
||||||
</WrapTab>
|
</WrapTab>
|
||||||
}
|
)}
|
||||||
|
|
||||||
<InputSearch onChange={setSearch} />
|
<InputSearch onChange={setSearch} />
|
||||||
{
|
{(entityUser.role == "supadmin" || entityUser.role == "developer") && (
|
||||||
(entityUser.role == "supadmin" || entityUser.role == "developer") &&
|
<View style={[Styles.mv05, Styles.rowItemsCenter]}>
|
||||||
<View style={[Styles.mv05, Styles.rowOnly]}>
|
<Text style={{ color: colors.dimmed, fontSize: 12 }}>Filter:</Text>
|
||||||
<Text>Filter :</Text>
|
|
||||||
<LabelStatus size="small" category="secondary" text={nameGroup} style={[Styles.mh05]} />
|
<LabelStatus size="small" category="secondary" text={nameGroup} style={[Styles.mh05]} />
|
||||||
</View>
|
</View>
|
||||||
}
|
)}
|
||||||
</View>
|
</View>
|
||||||
<View style={[Styles.flex2, Styles.mt05]}>
|
|
||||||
{
|
|
||||||
isLoading ?
|
|
||||||
arrSkeleton.map((item: any, i: number) => {
|
|
||||||
return (
|
|
||||||
<SkeletonContent key={i} />
|
|
||||||
)
|
|
||||||
})
|
|
||||||
:
|
|
||||||
flatData.length > 0
|
|
||||||
?
|
|
||||||
<VirtualizedList
|
|
||||||
data={flatData}
|
|
||||||
getItemCount={() => flatData.length}
|
|
||||||
getItem={getItem}
|
|
||||||
renderItem={({ item, index }: { item: Props, index: number }) => {
|
|
||||||
return (
|
|
||||||
<BorderBottomItem
|
|
||||||
bgColor="transparent"
|
|
||||||
key={index}
|
|
||||||
onPress={() => { router.push(`/discussion/${item.id}`) }}
|
|
||||||
borderType="bottom"
|
|
||||||
icon={
|
|
||||||
<MaterialIcons name="chat" size={25} color={colors.text} />
|
|
||||||
}
|
|
||||||
title={item.title}
|
|
||||||
subtitle={
|
|
||||||
status != "false" && <LabelStatus category={item.status === 1 ? "success" : "error"} text={item.status === 1 ? "BUKA" : "TUTUP"} size="small" />
|
|
||||||
}
|
|
||||||
rightTopInfo={item.createdAt}
|
|
||||||
desc={item.desc?.replace(/<[^>]*>?/gm, ' ').replace(/\r?\n|\r/g, ' ')}
|
|
||||||
leftBottomInfo={
|
|
||||||
<View style={[Styles.rowItemsCenter]}>
|
|
||||||
<Ionicons name="chatbox-ellipses-outline" size={18} color={colors.dimmed} style={Styles.mr05} />
|
|
||||||
<Text style={[Styles.textInformation, { color: colors.dimmed }, Styles.mb05]}>Diskusikan</Text>
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
rightBottomInfo={`${item.total_komentar} Komentar`}
|
|
||||||
|
|
||||||
/>
|
{/* List */}
|
||||||
)
|
<View style={[Styles.flex1, Styles.ph15, { paddingTop: 8 }]}>
|
||||||
}}
|
{isLoading ? (
|
||||||
keyExtractor={(item, index) => String(index)}
|
[0, 1, 2, 3, 4].map((_, i) => <SkeletonContent key={i} />)
|
||||||
onEndReached={loadMoreData}
|
) : flatData.length === 0 ? (
|
||||||
onEndReachedThreshold={0.5}
|
<View style={[Styles.contentItemCenter, Styles.mt30]}>
|
||||||
showsVerticalScrollIndicator={false}
|
<Feather name="message-circle" size={42} color={colors.icon + '40'} />
|
||||||
refreshControl={
|
<Text style={[Styles.mt10, { color: colors.dimmed, fontSize: 14 }]}>
|
||||||
<RefreshControl
|
Tidak ada diskusi
|
||||||
refreshing={refreshing}
|
</Text>
|
||||||
onRefresh={handleRefresh}
|
</View>
|
||||||
tintColor={colors.icon}
|
) : (
|
||||||
/>
|
<FlatList
|
||||||
}
|
data={flatData}
|
||||||
|
keyExtractor={(_, i) => String(i)}
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
onEndReached={() => {
|
||||||
|
if (hasNextPage && !isFetchingNextPage) fetchNextPage()
|
||||||
|
}}
|
||||||
|
onEndReachedThreshold={0.5}
|
||||||
|
refreshControl={
|
||||||
|
<RefreshControl
|
||||||
|
refreshing={refreshing}
|
||||||
|
onRefresh={handleRefresh}
|
||||||
|
tintColor={colors.icon}
|
||||||
/>
|
/>
|
||||||
:
|
}
|
||||||
<Text style={[Styles.textDefault, Styles.textCenter, { color: colors.dimmed }]}>Tidak ada data</Text>
|
ItemSeparatorComponent={() => <View style={Styles.discussionSeparator} />}
|
||||||
}
|
renderItem={({ item }: { item: Props }) => (
|
||||||
|
<Pressable
|
||||||
|
onPress={() => router.push(`/discussion/${item.id}`)}
|
||||||
|
style={({ pressed }) => [
|
||||||
|
Styles.discussionCard,
|
||||||
|
{
|
||||||
|
backgroundColor: pressed ? colors.icon + '10' : colors.card,
|
||||||
|
borderColor: colors.icon + '20',
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{/* Top row: icon + title + status badge */}
|
||||||
|
<View style={[Styles.rowItemsCenter, Styles.mb08]}>
|
||||||
|
{/* Discussion icon */}
|
||||||
|
<View style={[Styles.discussionIconCircle, { backgroundColor: colors.icon + '20' }]}>
|
||||||
|
<Feather name="message-circle" size={20} color={colors.icon} />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Title + status badge */}
|
||||||
|
<View style={[Styles.flex1, { marginLeft: 10 }]}>
|
||||||
|
<Text style={[Styles.textDefaultSemiBold, { color: colors.text }]} numberOfLines={1}>
|
||||||
|
{item.title}
|
||||||
|
</Text>
|
||||||
|
{status !== "false" && (
|
||||||
|
<View style={[Styles.discussionStatusPill, { borderColor: isOpen(item) ? '#10B981' : colors.dimmed + '80' }]}>
|
||||||
|
<Text style={[Styles.discussionStatusText, { color: isOpen(item) ? '#10B981' : colors.dimmed }]}>
|
||||||
|
{isOpen(item) ? 'Buka' : 'Tutup'}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Description */}
|
||||||
|
{item.desc ? (
|
||||||
|
<Text
|
||||||
|
style={[Styles.textMediumNormal, Styles.discussionCardIndent, { color: colors.dimmed, marginBottom: 10 }]}
|
||||||
|
numberOfLines={2}
|
||||||
|
>
|
||||||
|
{item.desc.replace(/<[^>]*>?/gm, ' ').replace(/\r?\n|\r/g, ' ')}
|
||||||
|
</Text>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{/* Bottom row: comment count + date */}
|
||||||
|
<View style={[Styles.rowItemsCenter, Styles.rowSpaceBetween, Styles.discussionCardIndent]}>
|
||||||
|
<View style={Styles.rowItemsCenter}>
|
||||||
|
<Feather name="message-square" size={14} color={colors.dimmed} />
|
||||||
|
<Text style={[Styles.discussionCommentText, { color: colors.dimmed }]}>
|
||||||
|
{item.total_komentar} Komentar
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Text style={[Styles.discussionDateText, { color: colors.dimmed }]}>
|
||||||
|
{item.createdAt}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</Pressable>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import AppHeader from "@/components/AppHeader";
|
import AppHeader from "@/components/AppHeader";
|
||||||
import BorderBottomItem from "@/components/borderBottomItem";
|
|
||||||
import BorderBottomItem2 from "@/components/borderBottomItem2";
|
import BorderBottomItem2 from "@/components/borderBottomItem2";
|
||||||
import HeaderRightDiscussionDetail from "@/components/discussion/headerDiscussionDetail";
|
import HeaderRightDiscussionDetail from "@/components/discussion/headerDiscussionDetail";
|
||||||
import DrawerBottom from "@/components/drawerBottom";
|
import DrawerBottom from "@/components/drawerBottom";
|
||||||
import ImageUser from "@/components/imageNew";
|
import ImageUser from "@/components/imageNew";
|
||||||
import { InputForm } from "@/components/inputForm";
|
import { InputForm } from "@/components/inputForm";
|
||||||
import LabelStatus from "@/components/labelStatus";
|
|
||||||
import MenuItemRow from "@/components/menuItemRow";
|
import MenuItemRow from "@/components/menuItemRow";
|
||||||
import ModalConfirmation from "@/components/ModalConfirmation";
|
import ModalConfirmation from "@/components/ModalConfirmation";
|
||||||
import Skeleton from "@/components/skeleton";
|
import Skeleton from "@/components/skeleton";
|
||||||
@@ -24,7 +22,7 @@ import {
|
|||||||
import { getDB } from "@/lib/firebaseDatabase";
|
import { getDB } from "@/lib/firebaseDatabase";
|
||||||
import { useAuthSession } from "@/providers/AuthProvider";
|
import { useAuthSession } from "@/providers/AuthProvider";
|
||||||
import { useTheme } from "@/providers/ThemeProvider";
|
import { useTheme } from "@/providers/ThemeProvider";
|
||||||
import { Feather, Ionicons, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons";
|
import { Feather, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons";
|
||||||
import { ref } from "@react-native-firebase/database";
|
import { ref } from "@react-native-firebase/database";
|
||||||
import { useHeaderHeight } from '@react-navigation/elements';
|
import { useHeaderHeight } from '@react-navigation/elements';
|
||||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||||
@@ -87,24 +85,15 @@ export default function DiscussionDetail() {
|
|||||||
const [detailMore, setDetailMore] = useState<any>([])
|
const [detailMore, setDetailMore] = useState<any>([])
|
||||||
const entities = useSelector((state: any) => state.entities)
|
const entities = useSelector((state: any) => state.entities)
|
||||||
const [isVisible, setVisible] = useState(false)
|
const [isVisible, setVisible] = useState(false)
|
||||||
const [selectKomentar, setSelectKomentar] = useState({
|
const [selectKomentar, setSelectKomentar] = useState({ id: '', comment: '' })
|
||||||
id: '',
|
|
||||||
comment: ''
|
|
||||||
})
|
|
||||||
const [viewEdit, setViewEdit] = useState(false)
|
const [viewEdit, setViewEdit] = useState(false)
|
||||||
const [showDeleteModal, setShowDeleteModal] = useState(false)
|
const [showDeleteModal, setShowDeleteModal] = useState(false)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const onValueChange = reference.on('value', snapshot => {
|
const onValueChange = reference.on('value', snapshot => {
|
||||||
if (snapshot.val() == null) {
|
if (snapshot.val() == null) { reference.set({ trigger: true }) }
|
||||||
reference.set({ trigger: true })
|
|
||||||
}
|
|
||||||
handleLoadComment(false)
|
handleLoadComment(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Stop listening for updates when no longer required
|
|
||||||
return () => reference.off('value', onValueChange);
|
return () => reference.off('value', onValueChange);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -115,23 +104,12 @@ export default function DiscussionDetail() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function handleLoad(loading: boolean) {
|
async function handleLoad(loading: boolean) {
|
||||||
try {
|
try {
|
||||||
setLoading(loading)
|
setLoading(loading)
|
||||||
const hasil = await decryptToken(String(token?.current));
|
const hasil = await decryptToken(String(token?.current));
|
||||||
const response = await apiGetDiscussionOne({
|
const response = await apiGetDiscussionOne({ id: detail, user: hasil, cat: "data" });
|
||||||
id: detail,
|
const responseFile = await apiGetDiscussionOne({ id: detail, user: hasil, cat: "file" });
|
||||||
user: hasil,
|
|
||||||
cat: "data",
|
|
||||||
});
|
|
||||||
|
|
||||||
const responseFile = await apiGetDiscussionOne({
|
|
||||||
id: detail,
|
|
||||||
user: hasil,
|
|
||||||
cat: "file",
|
|
||||||
});
|
|
||||||
|
|
||||||
setData(response.data);
|
setData(response.data);
|
||||||
setFileDiscussion(responseFile.data)
|
setFileDiscussion(responseFile.data)
|
||||||
setIsCreator(response.data.createdBy == hasil);
|
setIsCreator(response.data.createdBy == hasil);
|
||||||
@@ -146,11 +124,7 @@ export default function DiscussionDetail() {
|
|||||||
try {
|
try {
|
||||||
setLoadingKomentar(loading)
|
setLoadingKomentar(loading)
|
||||||
const hasil = await decryptToken(String(token?.current));
|
const hasil = await decryptToken(String(token?.current));
|
||||||
const response = await apiGetDiscussionOne({
|
const response = await apiGetDiscussionOne({ id: detail, user: hasil, cat: "comment" });
|
||||||
id: detail,
|
|
||||||
user: hasil,
|
|
||||||
cat: "comment",
|
|
||||||
});
|
|
||||||
setDataComment(response.data);
|
setDataComment(response.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@@ -162,17 +136,8 @@ export default function DiscussionDetail() {
|
|||||||
async function handleCheckMember() {
|
async function handleCheckMember() {
|
||||||
try {
|
try {
|
||||||
const hasil = await decryptToken(String(token?.current));
|
const hasil = await decryptToken(String(token?.current));
|
||||||
const response = await apiGetDivisionOneFeature({
|
const response = await apiGetDivisionOneFeature({ id, user: hasil, cat: "check-member" });
|
||||||
id,
|
const response2 = await apiGetDivisionOneFeature({ id, user: hasil, cat: "check-admin" });
|
||||||
user: hasil,
|
|
||||||
cat: "check-member",
|
|
||||||
});
|
|
||||||
|
|
||||||
const response2 = await apiGetDivisionOneFeature({
|
|
||||||
id,
|
|
||||||
user: hasil,
|
|
||||||
cat: "check-admin",
|
|
||||||
});
|
|
||||||
setIsMemberDivision(response.data);
|
setIsMemberDivision(response.data);
|
||||||
setIsAdminDivision(response2.data);
|
setIsAdminDivision(response2.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -180,33 +145,18 @@ export default function DiscussionDetail() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => { handleLoad(false); }, [update.data]);
|
||||||
handleLoad(false);
|
useEffect(() => { handleLoad(true); handleLoadComment(true); handleCheckMember(); }, []);
|
||||||
}, [update.data]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
handleLoad(true)
|
|
||||||
handleLoadComment(true);
|
|
||||||
handleCheckMember();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
async function handleKomentar() {
|
async function handleKomentar() {
|
||||||
try {
|
try {
|
||||||
setLoadingSend(true);
|
setLoadingSend(true);
|
||||||
const hasil = await decryptToken(String(token?.current));
|
const hasil = await decryptToken(String(token?.current));
|
||||||
const response = await apiSendDiscussionCommentar({
|
const response = await apiSendDiscussionCommentar({ id: detail, data: { comment: komentar, user: hasil } });
|
||||||
id: detail,
|
if (response.success) { setKomentar(""); updateTrigger() }
|
||||||
data: { comment: komentar, user: hasil },
|
|
||||||
});
|
|
||||||
if (response.success) {
|
|
||||||
setKomentar("")
|
|
||||||
updateTrigger()
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
const message = error?.response?.data?.message || "Gagal menambahkan komentar"
|
Toast.show({ type: 'small', text1: error?.response?.data?.message || "Gagal menambahkan komentar" })
|
||||||
|
|
||||||
Toast.show({ type: 'small', text1: message })
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoadingSend(false);
|
setLoadingSend(false);
|
||||||
}
|
}
|
||||||
@@ -216,20 +166,11 @@ export default function DiscussionDetail() {
|
|||||||
try {
|
try {
|
||||||
setLoadingSend(true);
|
setLoadingSend(true);
|
||||||
const hasil = await decryptToken(String(token?.current));
|
const hasil = await decryptToken(String(token?.current));
|
||||||
const response = await apiEditDiscussionCommentar({
|
const response = await apiEditDiscussionCommentar({ id: selectKomentar.id, data: { comment: selectKomentar.comment, user: hasil } });
|
||||||
id: selectKomentar.id,
|
if (response.success) { updateTrigger() } else { Toast.show({ type: 'small', text1: response.message }) }
|
||||||
data: { comment: selectKomentar.comment, user: hasil },
|
} catch (error: any) {
|
||||||
});
|
|
||||||
if (response.success) {
|
|
||||||
updateTrigger()
|
|
||||||
} else {
|
|
||||||
Toast.show({ type: 'small', text1: response.message })
|
|
||||||
}
|
|
||||||
} catch (error : any ) {
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
const message = error?.response?.data?.message || "Gagal mengedit komentar"
|
Toast.show({ type: 'small', text1: error?.response?.data?.message || "Gagal mengedit komentar" })
|
||||||
|
|
||||||
Toast.show({ type: 'small', text1: message })
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoadingSend(false);
|
setLoadingSend(false);
|
||||||
handleViewEditKomentar()
|
handleViewEditKomentar()
|
||||||
@@ -240,20 +181,11 @@ export default function DiscussionDetail() {
|
|||||||
try {
|
try {
|
||||||
setLoadingSend(true);
|
setLoadingSend(true);
|
||||||
const hasil = await decryptToken(String(token?.current));
|
const hasil = await decryptToken(String(token?.current));
|
||||||
const response = await apiDeleteDiscussionCommentar({
|
const response = await apiDeleteDiscussionCommentar({ id: selectKomentar.id, data: { user: hasil } });
|
||||||
id: selectKomentar.id,
|
if (response.success) { updateTrigger() } else { Toast.show({ type: 'small', text1: response.message }) }
|
||||||
data: { user: hasil },
|
} catch (error: any) {
|
||||||
});
|
|
||||||
if (response.success) {
|
|
||||||
updateTrigger()
|
|
||||||
} else {
|
|
||||||
Toast.show({ type: 'small', text1: response.message })
|
|
||||||
}
|
|
||||||
} catch (error : any ) {
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
const message = error?.response?.data?.message || "Gagal menghapus komentar"
|
Toast.show({ type: 'small', text1: error?.response?.data?.message || "Gagal menghapus komentar" })
|
||||||
|
|
||||||
Toast.show({ type: 'small', text1: message })
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoadingSend(false)
|
setLoadingSend(false)
|
||||||
setVisible(false)
|
setVisible(false)
|
||||||
@@ -265,13 +197,11 @@ export default function DiscussionDetail() {
|
|||||||
setVisible(true)
|
setVisible(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function handleViewEditKomentar() {
|
function handleViewEditKomentar() {
|
||||||
setVisible(false)
|
setVisible(false)
|
||||||
setViewEdit(!viewEdit)
|
setViewEdit(!viewEdit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const handleRefresh = async () => {
|
const handleRefresh = async () => {
|
||||||
setRefreshing(true)
|
setRefreshing(true)
|
||||||
handleLoad(false)
|
handleLoad(false)
|
||||||
@@ -280,27 +210,15 @@ export default function DiscussionDetail() {
|
|||||||
setRefreshing(false)
|
setRefreshing(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const canWrite = data?.status != 2 && data?.isActive && ((entityUser.role != "user" && entityUser.role != "coadmin") || isMemberDivision)
|
||||||
|
const isOpen = data?.status === 1
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
options={{
|
options={{
|
||||||
// headerLeft: () => (
|
|
||||||
// <ButtonBackHeader
|
|
||||||
// onPress={() => {
|
|
||||||
// router.back();
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// ),
|
|
||||||
headerTitle: "Diskusi",
|
headerTitle: "Diskusi",
|
||||||
headerTitleAlign: "center",
|
headerTitleAlign: "center",
|
||||||
// headerRight: () =>
|
|
||||||
// (entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision || isCreator ?
|
|
||||||
// <HeaderRightDiscussionDetail
|
|
||||||
// id={detail}
|
|
||||||
// status={data?.status}
|
|
||||||
// isActive={data?.isActive}
|
|
||||||
// /> : (<></>)
|
|
||||||
// ,
|
|
||||||
header: () => (
|
header: () => (
|
||||||
<AppHeader
|
<AppHeader
|
||||||
title="Diskusi"
|
title="Diskusi"
|
||||||
@@ -308,257 +226,177 @@ export default function DiscussionDetail() {
|
|||||||
onPressLeft={() => router.back()}
|
onPressLeft={() => router.back()}
|
||||||
right={
|
right={
|
||||||
((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision || isCreator) ?
|
((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision || isCreator) ?
|
||||||
<HeaderRightDiscussionDetail
|
<HeaderRightDiscussionDetail id={detail} status={data?.status} isActive={data?.isActive} /> : undefined
|
||||||
id={detail}
|
|
||||||
status={data?.status}
|
|
||||||
isActive={data?.isActive}
|
|
||||||
/> : (<></>)
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<View style={{ flex: 1, backgroundColor: colors.background }}>
|
<View style={[Styles.flex1, { backgroundColor: colors.background }]}>
|
||||||
<ScrollView
|
<ScrollView
|
||||||
refreshControl={
|
showsVerticalScrollIndicator={false}
|
||||||
<RefreshControl
|
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={handleRefresh} tintColor={colors.icon} />}
|
||||||
refreshing={refreshing}
|
|
||||||
onRefresh={handleRefresh}
|
|
||||||
tintColor={colors.icon}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<View style={[Styles.p15, Styles.mb100]}>
|
<View style={[Styles.p15]}>
|
||||||
{
|
{loading ? (
|
||||||
loading ?
|
<SkeletonContent />
|
||||||
<SkeletonContent />
|
) : (
|
||||||
:
|
<BorderBottomItem2
|
||||||
<BorderBottomItem2
|
dataFile={fileDiscussion}
|
||||||
dataFile={fileDiscussion}
|
descEllipsize={false}
|
||||||
descEllipsize={false}
|
borderType="all"
|
||||||
bgColor="white"
|
bgColor="white"
|
||||||
borderType="all"
|
icon={
|
||||||
icon={
|
<ImageUser src={`${ConstEnv.url_storage}/files/${data?.user_img}`} size="sm" />
|
||||||
<ImageUser
|
}
|
||||||
src={`${ConstEnv.url_storage}/files/${data?.user_img}`}
|
title={data?.username}
|
||||||
size="sm"
|
titleShowAll={true}
|
||||||
/>
|
subtitle={
|
||||||
}
|
<View style={[Styles.discussionStatusPill, {
|
||||||
title={data?.username}
|
borderColor: !data?.isActive ? '#F59E0B' : isOpen ? '#10B981' : colors.dimmed + '80',
|
||||||
subtitle={
|
}]}>
|
||||||
data?.isActive ? (
|
<Text style={[Styles.discussionStatusText, {
|
||||||
data?.status == 1 ? (
|
color: !data?.isActive ? '#F59E0B' : isOpen ? '#10B981' : colors.dimmed,
|
||||||
<LabelStatus category="success" text="BUKA" size="small" />
|
}]}>
|
||||||
) : (
|
{!data?.isActive ? 'Arsip' : isOpen ? 'Buka' : 'Tutup'}
|
||||||
<LabelStatus category="error" text="TUTUP" size="small" />
|
</Text>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
desc={data?.desc}
|
||||||
|
leftBottomInfo={
|
||||||
|
<View style={Styles.rowItemsCenter}>
|
||||||
|
<Feather name="message-square" size={14} color={colors.dimmed} style={Styles.mr05} />
|
||||||
|
<Text style={[Styles.textInformation, { color: colors.dimmed }]}>{dataComment.length} Komentar</Text>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
rightBottomInfo={<Text style={[Styles.textInformation, { color: colors.dimmed }]}>{data?.createdAt}</Text>}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<View style={Styles.mt10}>
|
||||||
|
{loadingKomentar ? (
|
||||||
|
arrSkeleton.map((_, i) => (
|
||||||
|
<Skeleton key={i} width={100} widthType="percent" height={40} borderRadius={5} />
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
dataComment.map((item, i) => (
|
||||||
|
<Pressable
|
||||||
|
key={i}
|
||||||
|
onPress={() => {
|
||||||
|
setDetailMore((prev: any) =>
|
||||||
|
prev.includes(item.id) ? prev.filter((id: string) => id !== item.id) : [...prev, item.id]
|
||||||
)
|
)
|
||||||
) : (
|
}}
|
||||||
<LabelStatus category="secondary" text="ARSIP" size="small" />
|
onLongPress={() => {
|
||||||
)
|
item.idUser == entities.id && data?.status != 2 && data?.isActive && handleMenuKomentar(item.id, item.comment)
|
||||||
}
|
}}
|
||||||
rightTopInfo={data?.createdAt}
|
style={({ pressed }) => [
|
||||||
desc={data?.desc}
|
Styles.discussionCommentCard,
|
||||||
leftBottomInfo={
|
{ backgroundColor: pressed ? colors.icon + '10' : colors.card, borderColor: colors.icon + '20' }
|
||||||
<View style={[Styles.rowItemsCenter]}>
|
]}
|
||||||
<Ionicons
|
>
|
||||||
name="chatbox-ellipses-outline"
|
<View style={Styles.flex1}>
|
||||||
size={18}
|
<View style={[Styles.rowSpaceBetween, Styles.itemsCenter, Styles.mb05]}>
|
||||||
color="grey"
|
<View style={[Styles.rowItemsCenter, { gap: 8, flex: 1, marginRight: 8 }]}>
|
||||||
style={Styles.mr05}
|
<ImageUser src={`${ConstEnv.url_storage}/files/${item.img}`} size="xs" />
|
||||||
/>
|
<Text style={[Styles.textMediumSemiBold, { color: colors.text }]} numberOfLines={1}>
|
||||||
<Text style={[Styles.textInformation, { color: colors.dimmed }, Styles.mb05]} >
|
{item.username}
|
||||||
{dataComment.length} Komentar
|
</Text>
|
||||||
|
{item.isEdited && (
|
||||||
|
<Text style={[Styles.discussionEditedText, { color: colors.dimmed }]}>diedit</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<Text style={[Styles.discussionDateText, { color: colors.dimmed, flexShrink: 0 }]}>
|
||||||
|
{item.createdAt}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Text style={[Styles.textDefault, { color: colors.text }]} numberOfLines={detailMore.includes(item.id) ? 0 : 3}>
|
||||||
|
{item.comment}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
}
|
</Pressable>
|
||||||
/>
|
))
|
||||||
}
|
)}
|
||||||
|
|
||||||
<View style={[Styles.mt10]}>
|
|
||||||
{
|
|
||||||
loadingKomentar ?
|
|
||||||
arrSkeleton.map((item, index) => (
|
|
||||||
<Skeleton key={index} width={100} widthType="percent" height={40} borderRadius={5} />
|
|
||||||
))
|
|
||||||
:
|
|
||||||
dataComment.map((item, index) => (
|
|
||||||
<BorderBottomItem
|
|
||||||
key={index}
|
|
||||||
borderType="all"
|
|
||||||
colorPress
|
|
||||||
icon={
|
|
||||||
<ImageUser
|
|
||||||
src={`${ConstEnv.url_storage}/files/${item.img}`}
|
|
||||||
size="xs"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
title={item.username}
|
|
||||||
rightTopInfo={item.createdAt}
|
|
||||||
desc={item.comment}
|
|
||||||
rightBottomInfo={item.isEdited ? "Edited" : ""}
|
|
||||||
descEllipsize={detailMore.includes(item.id) ? false : true}
|
|
||||||
bgColor="white"
|
|
||||||
onPress={() => {
|
|
||||||
setDetailMore((prev: any) => {
|
|
||||||
if (prev.includes(item.id)) {
|
|
||||||
return prev.filter((id: string) => id !== item.id)
|
|
||||||
} else {
|
|
||||||
return [...prev, item.id]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
onLongPress={() => {
|
|
||||||
item.idUser == entities.id && data?.status != 2 && data?.isActive && handleMenuKomentar(item.id, item.comment)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
<KeyboardAvoidingView
|
|
||||||
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
|
|
||||||
keyboardVerticalOffset={headerHeight}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
Styles.contentItemCenter,
|
|
||||||
Styles.w100,
|
|
||||||
{ backgroundColor: colors.background },
|
|
||||||
viewEdit && Styles.borderTop
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
viewEdit ?
|
|
||||||
<>
|
|
||||||
<View style={[Styles.w90, Styles.rowSpaceBetween, Styles.pv05]}>
|
|
||||||
<View style={[Styles.rowItemsCenter]}>
|
|
||||||
<Feather name="edit-3" color={colors.text} size={22} style={[Styles.mh05]} />
|
|
||||||
<Text style={[Styles.textMediumSemiBold]}>Edit Komentar</Text>
|
|
||||||
</View>
|
|
||||||
<Pressable onPress={() => handleViewEditKomentar()}>
|
|
||||||
<MaterialIcons name="close" color={colors.text} size={22} />
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
<InputForm
|
|
||||||
bg={colors.card}
|
|
||||||
type="default"
|
|
||||||
round
|
|
||||||
multiline
|
|
||||||
placeholder="Kirim Komentar"
|
|
||||||
onChange={(val: string) => setSelectKomentar({ ...selectKomentar, comment: val })}
|
|
||||||
value={selectKomentar.comment}
|
|
||||||
itemRight={
|
|
||||||
<Pressable
|
|
||||||
onPress={() => {
|
|
||||||
selectKomentar.comment != "" &&
|
|
||||||
!regexOnlySpacesOrEnter.test(selectKomentar.comment) &&
|
|
||||||
!loadingSend &&
|
|
||||||
data?.status != 2 &&
|
|
||||||
data?.isActive &&
|
|
||||||
(((entityUser.role == "user" ||
|
|
||||||
entityUser.role == "coadmin") &&
|
|
||||||
isMemberDivision) ||
|
|
||||||
entityUser.role == "admin" ||
|
|
||||||
entityUser.role == "supadmin" ||
|
|
||||||
entityUser.role == "developer" ||
|
|
||||||
entityUser.role == "cosupadmin") &&
|
|
||||||
handleEditKomentar();
|
|
||||||
}}
|
|
||||||
style={[
|
|
||||||
Platform.OS == 'android' && Styles.mb12,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<MaterialIcons
|
|
||||||
name="send"
|
|
||||||
size={25}
|
|
||||||
style={
|
|
||||||
[selectKomentar.comment == "" || regexOnlySpacesOrEnter.test(selectKomentar.comment) || loadingSend || ((entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision)
|
|
||||||
? { color: colors.dimmed }
|
|
||||||
: { color: colors.tint },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Pressable>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
:
|
|
||||||
data?.status != 2 && data?.isActive && ((entityUser.role != "user" && entityUser.role != "coadmin") ||
|
|
||||||
isMemberDivision)
|
|
||||||
?
|
|
||||||
<InputForm
|
|
||||||
type="default"
|
|
||||||
round
|
|
||||||
multiline
|
|
||||||
placeholder="Kirim Komentar"
|
|
||||||
onChange={setKomentar}
|
|
||||||
value={komentar}
|
|
||||||
itemRight={
|
|
||||||
<Pressable
|
|
||||||
onPress={() => {
|
|
||||||
komentar != "" &&
|
|
||||||
!regexOnlySpacesOrEnter.test(komentar) &&
|
|
||||||
!loadingSend &&
|
|
||||||
data?.status != 2 &&
|
|
||||||
data?.isActive &&
|
|
||||||
(((entityUser.role == "user" ||
|
|
||||||
entityUser.role == "coadmin") &&
|
|
||||||
isMemberDivision) ||
|
|
||||||
entityUser.role == "admin" ||
|
|
||||||
entityUser.role == "supadmin" ||
|
|
||||||
entityUser.role == "developer" ||
|
|
||||||
entityUser.role == "cosupadmin") &&
|
|
||||||
handleKomentar();
|
|
||||||
}}
|
|
||||||
style={[
|
|
||||||
Platform.OS == 'android' && Styles.mb12,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<MaterialIcons
|
|
||||||
name="send"
|
|
||||||
size={25}
|
|
||||||
style={
|
|
||||||
[komentar == "" || regexOnlySpacesOrEnter.test(komentar) || loadingSend || ((entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision)
|
|
||||||
? { color: colors.dimmed }
|
|
||||||
: { color: colors.tint }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Pressable>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
:
|
|
||||||
<View style={[Styles.pv20, { alignItems: 'center' }]}>
|
|
||||||
<Text style={[Styles.textInformation, { color: colors.dimmed }]}>
|
|
||||||
{
|
|
||||||
data?.status == 2 ? "Diskusi telah ditutup" : data?.isActive == false ? "Diskusi telah diarsipkan" : "Hanya anggota divisi yang dapat memberikan komentar"
|
|
||||||
}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined} keyboardVerticalOffset={headerHeight}>
|
||||||
|
<View style={[Styles.contentItemCenter, Styles.w100, { backgroundColor: colors.background }, viewEdit && Styles.borderTop]}>
|
||||||
|
{viewEdit ? (
|
||||||
|
<>
|
||||||
|
<View style={[Styles.w90, Styles.rowSpaceBetween, Styles.pv05]}>
|
||||||
|
<View style={Styles.rowItemsCenter}>
|
||||||
|
<Feather name="edit-3" color={colors.text} size={22} style={Styles.mh05} />
|
||||||
|
<Text style={Styles.textMediumSemiBold}>Edit Komentar</Text>
|
||||||
|
</View>
|
||||||
|
<Pressable onPress={() => handleViewEditKomentar()}>
|
||||||
|
<MaterialIcons name="close" color={colors.text} size={22} />
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
<InputForm
|
||||||
|
bg={colors.card}
|
||||||
|
type="default" round multiline
|
||||||
|
placeholder="Kirim Komentar"
|
||||||
|
onChange={(val: string) => setSelectKomentar({ ...selectKomentar, comment: val })}
|
||||||
|
value={selectKomentar.comment}
|
||||||
|
itemRight={
|
||||||
|
<Pressable
|
||||||
|
onPress={() => {
|
||||||
|
selectKomentar.comment != "" && !regexOnlySpacesOrEnter.test(selectKomentar.comment) && !loadingSend && data?.status != 2 && data?.isActive
|
||||||
|
&& (((entityUser.role == "user" || entityUser.role == "coadmin") && isMemberDivision) || entityUser.role == "admin" || entityUser.role == "supadmin" || entityUser.role == "developer" || entityUser.role == "cosupadmin")
|
||||||
|
&& handleEditKomentar();
|
||||||
|
}}
|
||||||
|
style={[Platform.OS == 'android' && Styles.mb12]}
|
||||||
|
>
|
||||||
|
<MaterialIcons name="send" size={25}
|
||||||
|
style={[
|
||||||
|
selectKomentar.comment == "" || regexOnlySpacesOrEnter.test(selectKomentar.comment) || loadingSend || ((entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision)
|
||||||
|
? { color: colors.dimmed } : { color: colors.tint },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Pressable>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : canWrite ? (
|
||||||
|
<InputForm
|
||||||
|
type="default" round multiline
|
||||||
|
placeholder="Kirim Komentar"
|
||||||
|
onChange={setKomentar} value={komentar}
|
||||||
|
itemRight={
|
||||||
|
<Pressable
|
||||||
|
onPress={() => {
|
||||||
|
komentar != "" && !regexOnlySpacesOrEnter.test(komentar) && !loadingSend && data?.status != 2 && data?.isActive
|
||||||
|
&& (((entityUser.role == "user" || entityUser.role == "coadmin") && isMemberDivision) || entityUser.role == "admin" || entityUser.role == "supadmin" || entityUser.role == "developer" || entityUser.role == "cosupadmin")
|
||||||
|
&& handleKomentar();
|
||||||
|
}}
|
||||||
|
style={[Platform.OS == 'android' && Styles.mb12]}
|
||||||
|
>
|
||||||
|
<MaterialIcons name="send" size={25}
|
||||||
|
style={[
|
||||||
|
komentar == "" || regexOnlySpacesOrEnter.test(komentar) || loadingSend || ((entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision)
|
||||||
|
? { color: colors.dimmed } : { color: colors.tint },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Pressable>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<View style={[Styles.pv20, Styles.itemsCenter]}>
|
||||||
|
<Text style={[Styles.textInformation, { color: colors.dimmed }]}>
|
||||||
|
{data?.status == 2 ? "Diskusi telah ditutup" : data?.isActive == false ? "Diskusi telah diarsipkan" : "Hanya anggota divisi yang dapat memberikan komentar"}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</KeyboardAvoidingView>
|
</KeyboardAvoidingView>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Komentar">
|
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Komentar">
|
||||||
<View style={Styles.rowItemsCenter}>
|
<View style={Styles.rowItemsCenter}>
|
||||||
<MenuItemRow
|
<MenuItemRow icon={<MaterialCommunityIcons name="pencil-outline" color={colors.text} size={25} />} title="Edit" onPress={() => handleViewEditKomentar()} />
|
||||||
icon={<MaterialCommunityIcons name="pencil-outline" color={colors.text} size={25} />}
|
<MenuItemRow icon={<MaterialIcons name="delete-outline" color={colors.text} size={25} />} title="Hapus" onPress={() => { setVisible(false); setTimeout(() => setShowDeleteModal(true), 600) }} />
|
||||||
title="Edit"
|
|
||||||
onPress={() => { handleViewEditKomentar() }}
|
|
||||||
/>
|
|
||||||
<MenuItemRow
|
|
||||||
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
|
|
||||||
title="Hapus"
|
|
||||||
onPress={() => {
|
|
||||||
setVisible(false)
|
|
||||||
setTimeout(() => {
|
|
||||||
setShowDeleteModal(true)
|
|
||||||
}, 600)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</DrawerBottom>
|
</DrawerBottom>
|
||||||
|
|
||||||
@@ -566,10 +404,7 @@ export default function DiscussionDetail() {
|
|||||||
visible={showDeleteModal}
|
visible={showDeleteModal}
|
||||||
title="Konfirmasi"
|
title="Konfirmasi"
|
||||||
message="Apakah anda yakin ingin menghapus komentar?"
|
message="Apakah anda yakin ingin menghapus komentar?"
|
||||||
onConfirm={() => {
|
onConfirm={() => { setShowDeleteModal(false); handleDeleteKomentar() }}
|
||||||
setShowDeleteModal(false)
|
|
||||||
handleDeleteKomentar()
|
|
||||||
}}
|
|
||||||
onCancel={() => setShowDeleteModal(false)}
|
onCancel={() => setShowDeleteModal(false)}
|
||||||
confirmText="Hapus"
|
confirmText="Hapus"
|
||||||
cancelText="Batal"
|
cancelText="Batal"
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import BorderBottomItem from "@/components/borderBottomItem";
|
|
||||||
import ButtonTab from "@/components/buttonTab";
|
import ButtonTab from "@/components/buttonTab";
|
||||||
import ImageUser from "@/components/imageNew";
|
import ImageUser from "@/components/imageNew";
|
||||||
import InputSearch from "@/components/inputSearch";
|
import InputSearch from "@/components/inputSearch";
|
||||||
import LabelStatus from "@/components/labelStatus";
|
|
||||||
import SkeletonContent from "@/components/skeletonContent";
|
import SkeletonContent from "@/components/skeletonContent";
|
||||||
import Text from "@/components/Text";
|
import Text from "@/components/Text";
|
||||||
import WrapTab from "@/components/wrapTab";
|
import WrapTab from "@/components/wrapTab";
|
||||||
@@ -11,13 +9,12 @@ import Styles from "@/constants/Styles";
|
|||||||
import { apiGetDiscussion, apiGetDivisionOneFeature } from "@/lib/api";
|
import { apiGetDiscussion, apiGetDivisionOneFeature } from "@/lib/api";
|
||||||
import { useAuthSession } from "@/providers/AuthProvider";
|
import { useAuthSession } from "@/providers/AuthProvider";
|
||||||
import { useTheme } from "@/providers/ThemeProvider";
|
import { useTheme } from "@/providers/ThemeProvider";
|
||||||
import { AntDesign, Feather, Ionicons } from "@expo/vector-icons";
|
import { AntDesign, Feather } from "@expo/vector-icons";
|
||||||
import { router, useLocalSearchParams } from "expo-router";
|
import { router, useLocalSearchParams } from "expo-router";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { RefreshControl, View, VirtualizedList } from "react-native";
|
import { FlatList, Pressable, RefreshControl, View } from "react-native";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string,
|
id: string,
|
||||||
title: string,
|
title: string,
|
||||||
@@ -30,7 +27,6 @@ type Props = {
|
|||||||
isActive: boolean
|
isActive: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default function DiscussionDivision() {
|
export default function DiscussionDivision() {
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
const { id, active } = useLocalSearchParams<{ id: string, active?: string }>()
|
const { id, active } = useLocalSearchParams<{ id: string, active?: string }>()
|
||||||
@@ -51,17 +47,8 @@ export default function DiscussionDivision() {
|
|||||||
async function handleCheckMember() {
|
async function handleCheckMember() {
|
||||||
try {
|
try {
|
||||||
const hasil = await decryptToken(String(token?.current));
|
const hasil = await decryptToken(String(token?.current));
|
||||||
const response = await apiGetDivisionOneFeature({
|
const response = await apiGetDivisionOneFeature({ id, user: hasil, cat: "check-member" });
|
||||||
id,
|
const response2 = await apiGetDivisionOneFeature({ id, user: hasil, cat: "check-admin" });
|
||||||
user: hasil,
|
|
||||||
cat: "check-member",
|
|
||||||
});
|
|
||||||
|
|
||||||
const response2 = await apiGetDivisionOneFeature({
|
|
||||||
id,
|
|
||||||
user: hasil,
|
|
||||||
cat: "check-admin",
|
|
||||||
});
|
|
||||||
setIsMemberDivision(response.data);
|
setIsMemberDivision(response.data);
|
||||||
setIsAdminDivision(response2.data);
|
setIsAdminDivision(response2.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -80,8 +67,6 @@ export default function DiscussionDivision() {
|
|||||||
setData(response.data)
|
setData(response.data)
|
||||||
} else if (thisPage > 1 && response.data.length > 0) {
|
} else if (thisPage > 1 && response.data.length > 0) {
|
||||||
setData([...data, ...response.data])
|
setData([...data, ...response.data])
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
@@ -91,26 +76,15 @@ export default function DiscussionDivision() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => { handleLoad(false, 1) }, [update.data])
|
||||||
handleLoad(false, 1)
|
useEffect(() => { handleLoad(true, 1) }, [status, search])
|
||||||
}, [update.data])
|
useEffect(() => { handleCheckMember() }, [])
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
handleLoad(true, 1)
|
|
||||||
}, [status, search])
|
|
||||||
|
|
||||||
const loadMoreData = () => {
|
const loadMoreData = () => {
|
||||||
if (waiting) return
|
if (waiting) return
|
||||||
setTimeout(() => {
|
setTimeout(() => { handleLoad(false, page + 1) }, 1000);
|
||||||
handleLoad(false, page + 1)
|
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
handleCheckMember()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const handleRefresh = async () => {
|
const handleRefresh = async () => {
|
||||||
setRefreshing(true)
|
setRefreshing(true)
|
||||||
handleLoad(false, 1)
|
handleLoad(false, 1)
|
||||||
@@ -118,100 +92,101 @@ export default function DiscussionDivision() {
|
|||||||
setRefreshing(false)
|
setRefreshing(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
const getItem = (_data: unknown, index: number): Props => ({
|
const isOpen = (item: Props) => item.status === 1
|
||||||
id: data[index].id,
|
|
||||||
title: data[index].title,
|
|
||||||
desc: data[index].desc,
|
|
||||||
status: data[index].status,
|
|
||||||
user_name: data[index].user_name,
|
|
||||||
img: data[index].img,
|
|
||||||
total_komentar: data[index].total_komentar,
|
|
||||||
createdAt: data[index].createdAt,
|
|
||||||
isActive: data[index].isActive,
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
|
<View style={[Styles.flex1, { backgroundColor: colors.background }]}>
|
||||||
{
|
{((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision) && (
|
||||||
((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision) &&
|
<View style={[Styles.ph15, { paddingTop: 12 }]}>
|
||||||
<View>
|
|
||||||
<WrapTab>
|
<WrapTab>
|
||||||
<ButtonTab
|
<ButtonTab
|
||||||
active={status == "false" ? "false" : "true"}
|
active={status == "false" ? "false" : "true"}
|
||||||
value="true"
|
value="true"
|
||||||
onPress={() => { setStatus("true") }}
|
onPress={() => setStatus("true")}
|
||||||
label="Aktif"
|
label="Aktif"
|
||||||
icon={<Feather name="check-circle" color={status == "false" ? colors.dimmed : 'white'} size={20} />}
|
icon={<Feather name="check-circle" color={status == "false" ? colors.dimmed : 'white'} size={20} />}
|
||||||
n={2} />
|
n={2}
|
||||||
|
/>
|
||||||
<ButtonTab
|
<ButtonTab
|
||||||
active={status == "false" ? "false" : "true"}
|
active={status == "false" ? "false" : "true"}
|
||||||
value="false"
|
value="false"
|
||||||
onPress={() => { setStatus("false") }}
|
onPress={() => setStatus("false")}
|
||||||
label="Arsip"
|
label="Arsip"
|
||||||
icon={<AntDesign name="closecircleo" color={status == "true" ? colors.dimmed : 'white'} size={20} />}
|
icon={<AntDesign name="closecircleo" color={status == "true" ? colors.dimmed : 'white'} size={20} />}
|
||||||
n={2} />
|
n={2}
|
||||||
|
/>
|
||||||
</WrapTab>
|
</WrapTab>
|
||||||
<InputSearch onChange={setSearch} />
|
<InputSearch onChange={setSearch} />
|
||||||
</View>
|
</View>
|
||||||
}
|
)}
|
||||||
|
|
||||||
|
<View style={[Styles.flex1, Styles.ph15, { paddingTop: 8 }]}>
|
||||||
|
{loading ? (
|
||||||
|
arrSkeleton.map((_, i) => <SkeletonContent key={i} />)
|
||||||
|
) : data.length === 0 ? (
|
||||||
|
<View style={[Styles.contentItemCenter, Styles.mt30]}>
|
||||||
|
<Feather name="message-circle" size={42} color={colors.icon + '40'} />
|
||||||
|
<Text style={[Styles.mt10, { color: colors.dimmed, fontSize: 14 }]}>
|
||||||
|
Tidak ada diskusi
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<FlatList
|
||||||
|
data={data}
|
||||||
|
keyExtractor={(_, i) => String(i)}
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
onEndReached={loadMoreData}
|
||||||
|
onEndReachedThreshold={0.5}
|
||||||
|
refreshControl={
|
||||||
|
<RefreshControl refreshing={refreshing} onRefresh={handleRefresh} tintColor={colors.icon} />
|
||||||
|
}
|
||||||
|
ItemSeparatorComponent={() => <View style={Styles.discussionSeparator} />}
|
||||||
|
renderItem={({ item }: { item: Props }) => (
|
||||||
|
<Pressable
|
||||||
|
onPress={() => router.push(`./discussion/${item.id}`)}
|
||||||
|
style={({ pressed }) => [
|
||||||
|
Styles.discussionCard,
|
||||||
|
{ backgroundColor: pressed ? colors.icon + '10' : colors.card, borderColor: colors.icon + '20' }
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<View style={[Styles.rowItemsCenter, Styles.mb08]}>
|
||||||
|
<ImageUser src={`${ConstEnv.url_storage}/files/${item.img}`} size="xs" />
|
||||||
|
<View style={[Styles.flex1, { marginLeft: 10 }]}>
|
||||||
|
<Text style={[Styles.textDefaultSemiBold, { color: colors.text }]} numberOfLines={1}>
|
||||||
|
{item.user_name}
|
||||||
|
</Text>
|
||||||
|
{status === "true" && (
|
||||||
|
<View style={[Styles.discussionStatusPill, { borderColor: isOpen(item) ? '#10B981' : colors.dimmed + '80' }]}>
|
||||||
|
<Text style={[Styles.discussionStatusText, { color: isOpen(item) ? '#10B981' : colors.dimmed }]}>
|
||||||
|
{isOpen(item) ? 'Buka' : 'Tutup'}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
<View style={[{ flex: 2 }, Styles.mt05]}>
|
{item.desc ? (
|
||||||
{
|
<Text style={[Styles.textMediumNormal, Styles.discussionCardIndent, { color: colors.dimmed, marginBottom: 10 }]} numberOfLines={2}>
|
||||||
loading ?
|
{item.desc}
|
||||||
arrSkeleton.map((item: any, i: number) => {
|
</Text>
|
||||||
return (
|
) : null}
|
||||||
<SkeletonContent key={i} />
|
|
||||||
)
|
<View style={[Styles.rowItemsCenter, Styles.rowSpaceBetween, Styles.discussionCardIndent]}>
|
||||||
})
|
<View style={Styles.rowItemsCenter}>
|
||||||
:
|
<Feather name="message-square" size={14} color={colors.dimmed} />
|
||||||
data.length > 0 ?
|
<Text style={[Styles.discussionCommentText, { color: colors.dimmed }]}>
|
||||||
<VirtualizedList
|
{item.total_komentar} Komentar
|
||||||
data={data}
|
</Text>
|
||||||
getItemCount={() => data.length}
|
</View>
|
||||||
getItem={getItem}
|
<Text style={[Styles.discussionDateText, { color: colors.dimmed }]}>
|
||||||
renderItem={({ item, index }: { item: Props, index: number }) => {
|
{item.createdAt}
|
||||||
return (
|
</Text>
|
||||||
<BorderBottomItem
|
</View>
|
||||||
key={index}
|
</Pressable>
|
||||||
onPress={() => { router.push(`./discussion/${item.id}`) }}
|
)}
|
||||||
borderType="bottom"
|
/>
|
||||||
icon={
|
)}
|
||||||
<ImageUser src={`${ConstEnv.url_storage}/files/${item.img}`} size="xs" />
|
|
||||||
}
|
|
||||||
title={item.user_name}
|
|
||||||
subtitle={
|
|
||||||
status == "true" ? item.status == 1 ? <LabelStatus category='success' text='BUKA' size="small" /> : <LabelStatus category='error' text='TUTUP' size="small" /> : <></>
|
|
||||||
}
|
|
||||||
rightTopInfo={item.createdAt}
|
|
||||||
desc={item.desc}
|
|
||||||
leftBottomInfo={
|
|
||||||
<View style={[Styles.rowItemsCenter]}>
|
|
||||||
<Ionicons name="chatbox-ellipses-outline" size={18} color={colors.dimmed} style={Styles.mr05} />
|
|
||||||
<Text style={[Styles.textInformation, { color: colors.dimmed }, Styles.mb05]}>Diskusikan</Text>
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
rightBottomInfo={item.total_komentar + ' Komentar'}
|
|
||||||
bgColor="transparent"
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
keyExtractor={(item, index) => String(index)}
|
|
||||||
onEndReached={loadMoreData}
|
|
||||||
onEndReachedThreshold={0.5}
|
|
||||||
showsVerticalScrollIndicator={false}
|
|
||||||
refreshControl={
|
|
||||||
<RefreshControl
|
|
||||||
refreshing={refreshing}
|
|
||||||
onRefresh={handleRefresh}
|
|
||||||
tintColor={colors.icon}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
:
|
|
||||||
(<Text style={[Styles.textDefault, Styles.mv10, { textAlign: "center", color: colors.dimmed }]}>Tidak ada diskusi</Text>)
|
|
||||||
}
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1113,6 +1113,62 @@ const Styles = StyleSheet.create({
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
marginLeft: 10,
|
marginLeft: 10,
|
||||||
},
|
},
|
||||||
|
discussionCard: {
|
||||||
|
borderRadius: 10,
|
||||||
|
borderWidth: 1,
|
||||||
|
padding: 14,
|
||||||
|
},
|
||||||
|
discussionIconCircle: {
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
borderRadius: 20,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexShrink: 0,
|
||||||
|
},
|
||||||
|
discussionIconCircleLg: {
|
||||||
|
width: 44,
|
||||||
|
height: 44,
|
||||||
|
borderRadius: 22,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
discussionStatusPill: {
|
||||||
|
alignSelf: 'flex-start',
|
||||||
|
marginTop: 3,
|
||||||
|
paddingHorizontal: 8,
|
||||||
|
paddingVertical: 2,
|
||||||
|
borderRadius: 20,
|
||||||
|
borderWidth: 1,
|
||||||
|
},
|
||||||
|
discussionStatusText: {
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
|
discussionCardIndent: {
|
||||||
|
marginLeft: 50,
|
||||||
|
},
|
||||||
|
discussionSeparator: {
|
||||||
|
height: 8,
|
||||||
|
},
|
||||||
|
discussionCommentText: {
|
||||||
|
fontSize: 12,
|
||||||
|
marginLeft: 5,
|
||||||
|
},
|
||||||
|
discussionDateText: {
|
||||||
|
fontSize: 11,
|
||||||
|
},
|
||||||
|
discussionCommentCard: {
|
||||||
|
borderRadius: 10,
|
||||||
|
borderWidth: 1,
|
||||||
|
padding: 12,
|
||||||
|
marginBottom: 8,
|
||||||
|
flexDirection: 'row',
|
||||||
|
},
|
||||||
|
discussionEditedText: {
|
||||||
|
fontSize: 10,
|
||||||
|
fontStyle: 'italic',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export default Styles;
|
export default Styles;
|
||||||
Reference in New Issue
Block a user