amalia/08-mei-26 #46

Merged
amaliadwiy merged 5 commits from amalia/08-mei-26 into join 2026-05-11 10:17:25 +08:00
9 changed files with 936 additions and 807 deletions
Showing only changes of commit d31a21cc9c - Show all commits

View File

@@ -1,11 +1,9 @@
import AppHeader from "@/components/AppHeader";
import BorderBottomItem from "@/components/borderBottomItem";
import BorderBottomItem2 from "@/components/borderBottomItem2";
import HeaderRightDiscussionGeneralDetail from "@/components/discussion_general/headerDiscussionDetail";
import DrawerBottom from "@/components/drawerBottom";
import ImageUser from "@/components/imageNew";
import { InputForm } from "@/components/inputForm";
import LabelStatus from "@/components/labelStatus";
import MenuItemRow from "@/components/menuItemRow";
import ModalConfirmation from "@/components/ModalConfirmation";
import Skeleton from "@/components/skeleton";
@@ -271,29 +269,36 @@ export default function DetailDiscussionGeneral() {
borderType="all"
bgColor="white"
icon={
<View style={[Styles.iconContent]}>
<MaterialIcons name="chat" size={25} color={'black'} />
<View style={[Styles.discussionIconCircleLg, { backgroundColor: colors.icon + '20' }]}>
<Feather name="message-circle" size={22} color={colors.icon} />
</View>
}
title={data?.title}
titleShowAll={true}
subtitle={
!data?.isActive ?
<LabelStatus category='warning' text='ARSIP' size="small" />
:
<LabelStatus category={data.status == 1 ? 'success' : 'error'} text={data.status == 1 ? 'BUKA' : 'TUTUP'} size="small" />
<View style={[Styles.discussionStatusPill, {
borderColor: !data?.isActive
? '#F59E0B'
: 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}
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]}>{dataKomentar.length} Komentar</Text>
<Feather name="message-square" size={14} color={colors.dimmed} style={Styles.mr05} />
<Text style={[Styles.textInformation, { color: colors.dimmed }]}>{dataKomentar.length} Komentar</Text>
</View>
}
rightBottomInfo={
<View style={[Styles.rowItemsCenter]}>
<Text style={[Styles.textInformation, { color: colors.dimmed }, Styles.mb05]}>{data?.createdAt}</Text>
</View>
<Text style={[Styles.textInformation, { color: colors.dimmed }]}>{data?.createdAt}</Text>
}
/>
}
@@ -306,36 +311,56 @@ export default function DetailDiscussionGeneral() {
)
})
:
dataKomentar.map((item, i) => {
return (
<BorderBottomItem
key={i}
borderType="all"
colorPress
icon={
<ImageUser src={`${ConstEnv.url_storage}/files/${item.img}`} size="xs" />
dataKomentar.map((item, i) => (
<Pressable
key={i}
onPress={() => {
setDetailMore((prev: any) =>
prev.includes(item.id)
? prev.filter((id: string) => id !== item.id)
: [...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}
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 style={Styles.flex1}>
{/* Name + time */}
<View style={[Styles.rowSpaceBetween, Styles.itemsCenter, Styles.mb05]}>
<View style={[Styles.rowItemsCenter, { gap: 8, flex: 1, marginRight: 8 }]}>
<ImageUser src={`${ConstEnv.url_storage}/files/${item.img}`} size="xs" />
<Text style={[Styles.textMediumSemiBold, { color: colors.text }]} numberOfLines={1}>
{item.username}
</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>
{/* Comment text */}
<Text
style={[Styles.textDefault, { color: colors.text }]}
numberOfLines={detailMore.includes(item.id) ? 0 : 3}
>
{item.comment}
</Text>
</View>
</Pressable>
))
}
</View>
</View>
@@ -372,15 +397,14 @@ export default function DetailDiscussionGeneral() {
multiline
focus={viewEdit}
itemRight={
<Pressable onPress={() => {
(!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,
]}
<Pressable
onPress={() => {
(!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]}
>
<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>
}
/>
@@ -398,15 +422,14 @@ export default function DetailDiscussionGeneral() {
multiline
focus={viewEdit}
itemRight={
<Pressable onPress={() => {
(!loadingSendKomentar && komentar != '' && !regexOnlySpacesOrEnter.test(komentar) && data?.status === 1 && data?.isActive && (memberDiscussion || (entityUser.role != "user" && entityUser.role != "coadmin")))
&& handleKomentar()
}}
style={[
Platform.OS == 'android' && Styles.mb12,
]}
<Pressable
onPress={() => {
(!loadingSendKomentar && komentar != '' && !regexOnlySpacesOrEnter.test(komentar) && data?.status === 1 && data?.isActive && (memberDiscussion || (entityUser.role != "user" && entityUser.role != "coadmin")))
&& handleKomentar()
}}
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>
}
/>

View File

@@ -1,23 +1,20 @@
import BorderBottomItem from "@/components/borderBottomItem";
import ButtonTab from "@/components/buttonTab";
import InputSearch from "@/components/inputSearch";
import LabelStatus from "@/components/labelStatus";
import SkeletonContent from "@/components/skeletonContent";
import Text from "@/components/Text";
import WrapTab from "@/components/wrapTab";
import { ColorsStatus } from "@/constants/ColorsStatus";
import Styles from "@/constants/Styles";
import { apiGetDiscussionGeneral } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
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 { router, useLocalSearchParams } from "expo-router";
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";
type Props = {
id: string
title: string
@@ -38,7 +35,6 @@ export default function Discussion() {
const [status, setStatus] = useState<'true' | 'false'>(active == 'false' ? 'false' : 'true')
const [refreshing, setRefreshing] = useState(false)
// TanStack Query for Discussions with Infinite Scroll
const {
data,
fetchNextPage,
@@ -50,12 +46,12 @@ export default function Discussion() {
queryKey: ['discussions', { status, search, group }],
queryFn: async ({ pageParam = 1 }) => {
const hasil = await decryptToken(String(token?.current))
const response = await apiGetDiscussionGeneral({
user: hasil,
active: status,
search: search,
group: String(group),
page: pageParam
const response = await apiGetDiscussionGeneral({
user: hasil,
active: status,
search: search,
group: String(group),
page: pageParam
})
return response;
},
@@ -67,17 +63,14 @@ export default function Discussion() {
staleTime: 0,
})
// Flatten pages into a single data array
const flatData = useMemo(() => {
return data?.pages.flatMap(page => page.data) || [];
}, [data])
// Get nameGroup from the first available page
const nameGroup = useMemo(() => {
return data?.pages[0]?.filter?.name || "";
}, [data])
// Refetch when manual update state changes
useEffect(() => {
refetch()
}, [update, refetch])
@@ -88,113 +81,129 @@ export default function Discussion() {
setRefreshing(false)
};
const loadMoreData = () => {
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,
})
const isOpen = (item: Props) => item.status === 1
return (
<View style={[Styles.p15, Styles.flex1, { backgroundColor: colors.background }]}>
<View>
{
entityUser.role != "user" && entityUser.role != "coadmin" &&
<View style={[Styles.flex1, { backgroundColor: colors.background }]}>
{/* Header controls */}
<View style={[Styles.ph15, { paddingTop: 12 }]}>
{entityUser.role != "user" && entityUser.role != "coadmin" && (
<WrapTab>
<ButtonTab
active={status == "false" ? "false" : "true"}
value="true"
onPress={() => { setStatus("true") }}
onPress={() => setStatus("true")}
label="Aktif"
icon={<Feather name="check-circle" color={status == "false" ? colors.dimmed : 'white'} size={20} />}
n={2} />
n={2}
/>
<ButtonTab
active={status == "false" ? "false" : "true"}
value="false"
onPress={() => { setStatus("false") }}
onPress={() => setStatus("false")}
label="Arsip"
icon={<AntDesign name="closecircleo" color={status == "true" ? colors.dimmed : 'white'} size={20} />}
n={2} />
n={2}
/>
</WrapTab>
}
)}
<InputSearch onChange={setSearch} />
{
(entityUser.role == "supadmin" || entityUser.role == "developer") &&
<View style={[Styles.mv05, Styles.rowOnly]}>
<Text>Filter :</Text>
{(entityUser.role == "supadmin" || entityUser.role == "developer") && (
<View style={[Styles.mv05, Styles.rowItemsCenter]}>
<Text style={{ color: colors.dimmed, fontSize: 12 }}>Filter:</Text>
<LabelStatus size="small" category="secondary" text={nameGroup} style={[Styles.mh05]} />
</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`}
/>
)
}}
keyExtractor={(item, index) => String(index)}
onEndReached={loadMoreData}
onEndReachedThreshold={0.5}
showsVerticalScrollIndicator={false}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.icon}
/>
}
{/* List */}
<View style={[Styles.flex1, Styles.ph15, { paddingTop: 8 }]}>
{isLoading ? (
[0, 1, 2, 3, 4].map((_, i) => <SkeletonContent key={i} />)
) : flatData.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={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 File

@@ -1,11 +1,9 @@
import AppHeader from "@/components/AppHeader";
import BorderBottomItem from "@/components/borderBottomItem";
import BorderBottomItem2 from "@/components/borderBottomItem2";
import HeaderRightDiscussionDetail from "@/components/discussion/headerDiscussionDetail";
import DrawerBottom from "@/components/drawerBottom";
import ImageUser from "@/components/imageNew";
import { InputForm } from "@/components/inputForm";
import LabelStatus from "@/components/labelStatus";
import MenuItemRow from "@/components/menuItemRow";
import ModalConfirmation from "@/components/ModalConfirmation";
import Skeleton from "@/components/skeleton";
@@ -24,7 +22,7 @@ import {
import { getDB } from "@/lib/firebaseDatabase";
import { useAuthSession } from "@/providers/AuthProvider";
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 { useHeaderHeight } from '@react-navigation/elements';
import { router, Stack, useLocalSearchParams } from "expo-router";
@@ -87,24 +85,15 @@ export default function DiscussionDetail() {
const [detailMore, setDetailMore] = useState<any>([])
const entities = useSelector((state: any) => state.entities)
const [isVisible, setVisible] = useState(false)
const [selectKomentar, setSelectKomentar] = useState({
id: '',
comment: ''
})
const [selectKomentar, setSelectKomentar] = useState({ id: '', comment: '' })
const [viewEdit, setViewEdit] = useState(false)
const [showDeleteModal, setShowDeleteModal] = useState(false)
useEffect(() => {
const onValueChange = reference.on('value', snapshot => {
if (snapshot.val() == null) {
reference.set({ trigger: true })
}
if (snapshot.val() == null) { reference.set({ trigger: true }) }
handleLoadComment(false)
});
// Stop listening for updates when no longer required
return () => reference.off('value', onValueChange);
}, []);
@@ -115,23 +104,12 @@ export default function DiscussionDetail() {
});
}
async function handleLoad(loading: boolean) {
try {
setLoading(loading)
const hasil = await decryptToken(String(token?.current));
const response = await apiGetDiscussionOne({
id: detail,
user: hasil,
cat: "data",
});
const responseFile = await apiGetDiscussionOne({
id: detail,
user: hasil,
cat: "file",
});
const response = await apiGetDiscussionOne({ id: detail, user: hasil, cat: "data" });
const responseFile = await apiGetDiscussionOne({ id: detail, user: hasil, cat: "file" });
setData(response.data);
setFileDiscussion(responseFile.data)
setIsCreator(response.data.createdBy == hasil);
@@ -146,11 +124,7 @@ export default function DiscussionDetail() {
try {
setLoadingKomentar(loading)
const hasil = await decryptToken(String(token?.current));
const response = await apiGetDiscussionOne({
id: detail,
user: hasil,
cat: "comment",
});
const response = await apiGetDiscussionOne({ id: detail, user: hasil, cat: "comment" });
setDataComment(response.data);
} catch (error) {
console.error(error);
@@ -162,17 +136,8 @@ export default function DiscussionDetail() {
async function handleCheckMember() {
try {
const hasil = await decryptToken(String(token?.current));
const response = await apiGetDivisionOneFeature({
id,
user: hasil,
cat: "check-member",
});
const response2 = await apiGetDivisionOneFeature({
id,
user: hasil,
cat: "check-admin",
});
const response = await apiGetDivisionOneFeature({ id, user: hasil, cat: "check-member" });
const response2 = await apiGetDivisionOneFeature({ id, user: hasil, cat: "check-admin" });
setIsMemberDivision(response.data);
setIsAdminDivision(response2.data);
} catch (error) {
@@ -180,33 +145,18 @@ export default function DiscussionDetail() {
}
}
useEffect(() => {
handleLoad(false);
}, [update.data]);
useEffect(() => {
handleLoad(true)
handleLoadComment(true);
handleCheckMember();
}, []);
useEffect(() => { handleLoad(false); }, [update.data]);
useEffect(() => { handleLoad(true); handleLoadComment(true); handleCheckMember(); }, []);
async function handleKomentar() {
try {
setLoadingSend(true);
const hasil = await decryptToken(String(token?.current));
const response = await apiSendDiscussionCommentar({
id: detail,
data: { comment: komentar, user: hasil },
});
if (response.success) {
setKomentar("")
updateTrigger()
}
const response = await apiSendDiscussionCommentar({ id: detail, data: { comment: komentar, user: hasil } });
if (response.success) { setKomentar(""); updateTrigger() }
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan komentar"
Toast.show({ type: 'small', text1: message })
Toast.show({ type: 'small', text1: error?.response?.data?.message || "Gagal menambahkan komentar" })
} finally {
setLoadingSend(false);
}
@@ -216,20 +166,11 @@ export default function DiscussionDetail() {
try {
setLoadingSend(true);
const hasil = await decryptToken(String(token?.current));
const response = await apiEditDiscussionCommentar({
id: selectKomentar.id,
data: { comment: selectKomentar.comment, user: hasil },
});
if (response.success) {
updateTrigger()
} else {
Toast.show({ type: 'small', text1: response.message })
}
} catch (error : any ) {
const response = await apiEditDiscussionCommentar({ id: selectKomentar.id, data: { comment: selectKomentar.comment, user: hasil } });
if (response.success) { updateTrigger() } else { Toast.show({ type: 'small', text1: response.message }) }
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengedit komentar"
Toast.show({ type: 'small', text1: message })
Toast.show({ type: 'small', text1: error?.response?.data?.message || "Gagal mengedit komentar" })
} finally {
setLoadingSend(false);
handleViewEditKomentar()
@@ -240,20 +181,11 @@ export default function DiscussionDetail() {
try {
setLoadingSend(true);
const hasil = await decryptToken(String(token?.current));
const response = await apiDeleteDiscussionCommentar({
id: selectKomentar.id,
data: { user: hasil },
});
if (response.success) {
updateTrigger()
} else {
Toast.show({ type: 'small', text1: response.message })
}
} catch (error : any ) {
const response = await apiDeleteDiscussionCommentar({ id: selectKomentar.id, data: { user: hasil } });
if (response.success) { updateTrigger() } else { Toast.show({ type: 'small', text1: response.message }) }
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menghapus komentar"
Toast.show({ type: 'small', text1: message })
Toast.show({ type: 'small', text1: error?.response?.data?.message || "Gagal menghapus komentar" })
} finally {
setLoadingSend(false)
setVisible(false)
@@ -265,13 +197,11 @@ export default function DiscussionDetail() {
setVisible(true)
}
function handleViewEditKomentar() {
setVisible(false)
setViewEdit(!viewEdit)
}
const handleRefresh = async () => {
setRefreshing(true)
handleLoad(false)
@@ -280,27 +210,15 @@ export default function DiscussionDetail() {
setRefreshing(false)
};
const canWrite = data?.status != 2 && data?.isActive && ((entityUser.role != "user" && entityUser.role != "coadmin") || isMemberDivision)
const isOpen = data?.status === 1
return (
<>
<Stack.Screen
options={{
// headerLeft: () => (
// <ButtonBackHeader
// onPress={() => {
// router.back();
// }}
// />
// ),
headerTitle: "Diskusi",
headerTitleAlign: "center",
// headerRight: () =>
// (entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision || isCreator ?
// <HeaderRightDiscussionDetail
// id={detail}
// status={data?.status}
// isActive={data?.isActive}
// /> : (<></>)
// ,
header: () => (
<AppHeader
title="Diskusi"
@@ -308,257 +226,177 @@ export default function DiscussionDetail() {
onPressLeft={() => router.back()}
right={
((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision || isCreator) ?
<HeaderRightDiscussionDetail
id={detail}
status={data?.status}
isActive={data?.isActive}
/> : (<></>)
<HeaderRightDiscussionDetail id={detail} status={data?.status} isActive={data?.isActive} /> : undefined
}
/>
)
}}
/>
<View style={{ flex: 1, backgroundColor: colors.background }}>
<View style={[Styles.flex1, { backgroundColor: colors.background }]}>
<ScrollView
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.icon}
/>
}
showsVerticalScrollIndicator={false}
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={handleRefresh} tintColor={colors.icon} />}
>
<View style={[Styles.p15, Styles.mb100]}>
{
loading ?
<SkeletonContent />
:
<BorderBottomItem2
dataFile={fileDiscussion}
descEllipsize={false}
bgColor="white"
borderType="all"
icon={
<ImageUser
src={`${ConstEnv.url_storage}/files/${data?.user_img}`}
size="sm"
/>
}
title={data?.username}
subtitle={
data?.isActive ? (
data?.status == 1 ? (
<LabelStatus category="success" text="BUKA" size="small" />
) : (
<LabelStatus category="error" text="TUTUP" size="small" />
<View style={[Styles.p15]}>
{loading ? (
<SkeletonContent />
) : (
<BorderBottomItem2
dataFile={fileDiscussion}
descEllipsize={false}
borderType="all"
bgColor="white"
icon={
<ImageUser src={`${ConstEnv.url_storage}/files/${data?.user_img}`} size="sm" />
}
title={data?.username}
titleShowAll={true}
subtitle={
<View style={[Styles.discussionStatusPill, {
borderColor: !data?.isActive ? '#F59E0B' : isOpen ? '#10B981' : colors.dimmed + '80',
}]}>
<Text style={[Styles.discussionStatusText, {
color: !data?.isActive ? '#F59E0B' : isOpen ? '#10B981' : colors.dimmed,
}]}>
{!data?.isActive ? 'Arsip' : isOpen ? 'Buka' : 'Tutup'}
</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" />
)
}
rightTopInfo={data?.createdAt}
desc={data?.desc}
leftBottomInfo={
<View style={[Styles.rowItemsCenter]}>
<Ionicons
name="chatbox-ellipses-outline"
size={18}
color="grey"
style={Styles.mr05}
/>
<Text style={[Styles.textInformation, { color: colors.dimmed }, Styles.mb05]} >
{dataComment.length} Komentar
}}
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' }
]}
>
<View style={Styles.flex1}>
<View style={[Styles.rowSpaceBetween, Styles.itemsCenter, Styles.mb05]}>
<View style={[Styles.rowItemsCenter, { gap: 8, flex: 1, marginRight: 8 }]}>
<ImageUser src={`${ConstEnv.url_storage}/files/${item.img}`} size="xs" />
<Text style={[Styles.textMediumSemiBold, { color: colors.text }]} numberOfLines={1}>
{item.username}
</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>
</View>
}
/>
}
<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)
}}
/>
))
}
</Pressable>
))
)}
</View>
</View>
</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>
</KeyboardAvoidingView>
</View>
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Komentar">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<MaterialCommunityIcons name="pencil-outline" color={colors.text} size={25} />}
title="Edit"
onPress={() => { handleViewEditKomentar() }}
/>
<MenuItemRow
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => {
setVisible(false)
setTimeout(() => {
setShowDeleteModal(true)
}, 600)
}}
/>
<MenuItemRow icon={<MaterialCommunityIcons name="pencil-outline" color={colors.text} size={25} />} title="Edit" onPress={() => handleViewEditKomentar()} />
<MenuItemRow icon={<MaterialIcons name="delete-outline" color={colors.text} size={25} />} title="Hapus" onPress={() => { setVisible(false); setTimeout(() => setShowDeleteModal(true), 600) }} />
</View>
</DrawerBottom>
@@ -566,10 +404,7 @@ export default function DiscussionDetail() {
visible={showDeleteModal}
title="Konfirmasi"
message="Apakah anda yakin ingin menghapus komentar?"
onConfirm={() => {
setShowDeleteModal(false)
handleDeleteKomentar()
}}
onConfirm={() => { setShowDeleteModal(false); handleDeleteKomentar() }}
onCancel={() => setShowDeleteModal(false)}
confirmText="Hapus"
cancelText="Batal"

View File

@@ -1,8 +1,6 @@
import BorderBottomItem from "@/components/borderBottomItem";
import ButtonTab from "@/components/buttonTab";
import ImageUser from "@/components/imageNew";
import InputSearch from "@/components/inputSearch";
import LabelStatus from "@/components/labelStatus";
import SkeletonContent from "@/components/skeletonContent";
import Text from "@/components/Text";
import WrapTab from "@/components/wrapTab";
@@ -11,13 +9,12 @@ import Styles from "@/constants/Styles";
import { apiGetDiscussion, apiGetDivisionOneFeature } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
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 { useEffect, useState } from "react";
import { RefreshControl, View, VirtualizedList } from "react-native";
import { FlatList, Pressable, RefreshControl, View } from "react-native";
import { useSelector } from "react-redux";
type Props = {
id: string,
title: string,
@@ -30,7 +27,6 @@ type Props = {
isActive: boolean
}
export default function DiscussionDivision() {
const { colors } = useTheme();
const { id, active } = useLocalSearchParams<{ id: string, active?: string }>()
@@ -51,17 +47,8 @@ export default function DiscussionDivision() {
async function handleCheckMember() {
try {
const hasil = await decryptToken(String(token?.current));
const response = await apiGetDivisionOneFeature({
id,
user: hasil,
cat: "check-member",
});
const response2 = await apiGetDivisionOneFeature({
id,
user: hasil,
cat: "check-admin",
});
const response = await apiGetDivisionOneFeature({ id, user: hasil, cat: "check-member" });
const response2 = await apiGetDivisionOneFeature({ id, user: hasil, cat: "check-admin" });
setIsMemberDivision(response.data);
setIsAdminDivision(response2.data);
} catch (error) {
@@ -80,8 +67,6 @@ export default function DiscussionDivision() {
setData(response.data)
} else if (thisPage > 1 && response.data.length > 0) {
setData([...data, ...response.data])
} else {
return;
}
} catch (error) {
console.error(error)
@@ -91,26 +76,15 @@ export default function DiscussionDivision() {
}
}
useEffect(() => {
handleLoad(false, 1)
}, [update.data])
useEffect(() => {
handleLoad(true, 1)
}, [status, search])
useEffect(() => { handleLoad(false, 1) }, [update.data])
useEffect(() => { handleLoad(true, 1) }, [status, search])
useEffect(() => { handleCheckMember() }, [])
const loadMoreData = () => {
if (waiting) return
setTimeout(() => {
handleLoad(false, page + 1)
}, 1000);
setTimeout(() => { handleLoad(false, page + 1) }, 1000);
}
useEffect(() => {
handleCheckMember()
}, [])
const handleRefresh = async () => {
setRefreshing(true)
handleLoad(false, 1)
@@ -118,100 +92,101 @@ export default function DiscussionDivision() {
setRefreshing(false)
};
const getItem = (_data: unknown, index: number): Props => ({
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,
})
const isOpen = (item: Props) => item.status === 1
return (
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
{
((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision) &&
<View>
<View style={[Styles.flex1, { backgroundColor: colors.background }]}>
{((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision) && (
<View style={[Styles.ph15, { paddingTop: 12 }]}>
<WrapTab>
<ButtonTab
active={status == "false" ? "false" : "true"}
value="true"
onPress={() => { setStatus("true") }}
onPress={() => setStatus("true")}
label="Aktif"
icon={<Feather name="check-circle" color={status == "false" ? colors.dimmed : 'white'} size={20} />}
n={2} />
n={2}
/>
<ButtonTab
active={status == "false" ? "false" : "true"}
value="false"
onPress={() => { setStatus("false") }}
onPress={() => setStatus("false")}
label="Arsip"
icon={<AntDesign name="closecircleo" color={status == "true" ? colors.dimmed : 'white'} size={20} />}
n={2} />
n={2}
/>
</WrapTab>
<InputSearch onChange={setSearch} />
</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]}>
{
loading ?
arrSkeleton.map((item: any, i: number) => {
return (
<SkeletonContent key={i} />
)
})
:
data.length > 0 ?
<VirtualizedList
data={data}
getItemCount={() => data.length}
getItem={getItem}
renderItem={({ item, index }: { item: Props, index: number }) => {
return (
<BorderBottomItem
key={index}
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>)
}
{item.desc ? (
<Text style={[Styles.textMediumNormal, Styles.discussionCardIndent, { color: colors.dimmed, marginBottom: 10 }]} numberOfLines={2}>
{item.desc}
</Text>
) : null}
<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 File

@@ -1113,6 +1113,62 @@ const Styles = StyleSheet.create({
flex: 1,
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;