- redesign discussion/member/[id]: flat list airy, bubble avatar row, header jumlah anggota, button tambah ikuti pola create - redesign division/[id]/info: sectionCard deskripsi, list anggota dengan role label, drawer menu konsisten - fix division/[id]/add-member: border warna mengikuti tema
196 lines
9.2 KiB
TypeScript
196 lines
9.2 KiB
TypeScript
import AppHeader from "@/components/AppHeader";
|
|
import DrawerBottom from "@/components/drawerBottom";
|
|
import ImageUser from "@/components/imageNew";
|
|
import MenuItemRow from "@/components/menuItemRow";
|
|
import ModalConfirmation from "@/components/ModalConfirmation";
|
|
import Text from '@/components/Text';
|
|
import { ConstEnv } from "@/constants/ConstEnv";
|
|
import Styles from "@/constants/Styles";
|
|
import { apiDeleteMemberDiscussionGeneral, apiGetDiscussionGeneralOne } from "@/lib/api";
|
|
import { useAuthSession } from "@/providers/AuthProvider";
|
|
import { useTheme } from "@/providers/ThemeProvider";
|
|
import { MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons";
|
|
import { router, Stack, useLocalSearchParams } from "expo-router";
|
|
import { useEffect, useState } from "react";
|
|
import { Pressable, SafeAreaView, ScrollView, View } from "react-native";
|
|
import Toast from "react-native-toast-message";
|
|
import { useSelector } from "react-redux";
|
|
|
|
type Props = {
|
|
idUser: string,
|
|
name: string,
|
|
img: string
|
|
}
|
|
|
|
const SKELETON_COUNT = 5
|
|
|
|
export default function MemberDiscussionDetail() {
|
|
const { token, decryptToken } = useAuthSession()
|
|
const { colors } = useTheme();
|
|
const entityUser = useSelector((state: any) => state.user)
|
|
const { id } = useLocalSearchParams<{ id: string }>()
|
|
const [data, setData] = useState<Props[]>([])
|
|
const [isModal, setModal] = useState(false)
|
|
const [chooseUser, setChooseUser] = useState({ idUser: '', name: '', img: '' })
|
|
const update = useSelector((state: any) => state.discussionGeneralDetailUpdate)
|
|
const [loading, setLoading] = useState(true)
|
|
const [showDeleteModal, setShowDeleteModal] = useState(false)
|
|
const canManage = entityUser.role !== "user" && entityUser.role !== "coadmin"
|
|
|
|
async function handleLoad(showLoadingIndicator: boolean) {
|
|
try {
|
|
setLoading(showLoadingIndicator)
|
|
const hasil = await decryptToken(String(token?.current))
|
|
const response = await apiGetDiscussionGeneralOne({ id: id, user: hasil, cat: 'anggota' })
|
|
setData(response.data)
|
|
} catch (error) {
|
|
console.error(error)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
useEffect(() => { handleLoad(false) }, [update]);
|
|
useEffect(() => { handleLoad(true) }, []);
|
|
|
|
async function handleDeleteUser() {
|
|
try {
|
|
const hasil = await decryptToken(String(token?.current))
|
|
await apiDeleteMemberDiscussionGeneral({ user: hasil, idUser: chooseUser.idUser }, id)
|
|
Toast.show({ type: 'small', text1: 'Berhasil mengeluarkan anggota dari diskusi' })
|
|
handleLoad(false)
|
|
} catch (error: any) {
|
|
console.error(error);
|
|
Toast.show({ type: 'small', text1: error?.response?.data?.message || "Gagal mengeluarkan anggota" })
|
|
} finally {
|
|
setModal(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<SafeAreaView style={[Styles.flex1, { backgroundColor: colors.background }]}>
|
|
<Stack.Screen
|
|
options={{
|
|
header: () => (
|
|
<AppHeader
|
|
title="Anggota Diskusi"
|
|
showBack={true}
|
|
onPressLeft={() => router.back()}
|
|
/>
|
|
)
|
|
}}
|
|
/>
|
|
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100, Styles.flex1, { backgroundColor: colors.background }]}>
|
|
<View style={[Styles.p15, Styles.mb100]}>
|
|
|
|
{/* Tombol tambah anggota */}
|
|
{canManage && (
|
|
<View style={[Styles.wrapPaper, Styles.sectionCard, Styles.mb15,
|
|
{ backgroundColor: colors.card, borderColor: colors.icon + '18' }]}>
|
|
<Pressable
|
|
onPress={() => router.push(`/discussion/add-member/${id}`)}
|
|
style={Styles.sectionActionRow}
|
|
>
|
|
<View style={[Styles.sectionIconBox, { backgroundColor: colors.icon + '18' }]}>
|
|
<MaterialCommunityIcons name="account-plus-outline" size={18} color={colors.icon} />
|
|
</View>
|
|
<View style={Styles.flex1}>
|
|
<Text style={[Styles.textDefaultSemiBold, { color: colors.text }]}>Tambah Anggota</Text>
|
|
</View>
|
|
<MaterialCommunityIcons name="chevron-right" size={18} color={colors.dimmed} />
|
|
</Pressable>
|
|
</View>
|
|
)}
|
|
|
|
{/* Full list */}
|
|
<View style={[Styles.wrapPaper, Styles.sectionCard,
|
|
{ backgroundColor: colors.card, borderColor: colors.icon + '18', padding: 0, overflow: 'hidden' }]}>
|
|
<View style={[Styles.sectionActionRow, { padding: 16, borderBottomWidth: 1, borderBottomColor: colors.icon + '14' }]}>
|
|
<View style={[Styles.sectionIconBox, { backgroundColor: colors.dimmed + '18' }]}>
|
|
<MaterialIcons name="people" size={18} color={colors.dimmed} />
|
|
</View>
|
|
<Text style={[Styles.textDefaultSemiBold, Styles.flex1, { color: colors.text }]}>Anggota</Text>
|
|
{!loading && (
|
|
<Text style={[Styles.textMediumNormal, { color: colors.dimmed }]}>{data.length} anggota</Text>
|
|
)}
|
|
</View>
|
|
{loading
|
|
? Array.from({ length: SKELETON_COUNT }).map((_, i) => (
|
|
<View
|
|
key={i}
|
|
style={[Styles.rowItemsCenter, Styles.ph15,
|
|
{ paddingVertical: 14, gap: 14, borderBottomWidth: i < SKELETON_COUNT - 1 ? 1 : 0, borderBottomColor: colors.icon + '14' }]}
|
|
>
|
|
<View style={[Styles.userProfileExtraSmall, { backgroundColor: colors.icon + '20', borderRadius: 100 }]} />
|
|
<View style={{ height: 13, borderRadius: 6, flex: 1, backgroundColor: colors.icon + '20', maxWidth: 140 + (i % 3) * 30 }} />
|
|
</View>
|
|
))
|
|
: data.length === 0
|
|
? (
|
|
<View style={[Styles.contentItemCenter, { paddingVertical: 40 }]}>
|
|
<MaterialIcons name="people-outline" size={34} color={colors.icon + '50'} />
|
|
<Text style={[Styles.textMediumNormal, Styles.mt10, { color: colors.dimmed }]}>Belum ada anggota</Text>
|
|
</View>
|
|
)
|
|
: data.map((item, index) => (
|
|
<Pressable
|
|
key={index}
|
|
onPress={() => { setChooseUser(item); setModal(true) }}
|
|
style={({ pressed }) => [
|
|
Styles.rowItemsCenter, Styles.ph15,
|
|
{
|
|
paddingVertical: 13, gap: 14,
|
|
borderBottomWidth: index < data.length - 1 ? 1 : 0,
|
|
borderBottomColor: colors.icon + '14',
|
|
backgroundColor: pressed ? colors.icon + '0E' : 'transparent',
|
|
},
|
|
]}
|
|
>
|
|
<ImageUser src={`${ConstEnv.url_storage}/files/${item.img}`} size="xs" />
|
|
<Text style={[Styles.textDefault, Styles.flex1, { color: colors.text }]} numberOfLines={1}>
|
|
{item.name}
|
|
</Text>
|
|
<MaterialCommunityIcons name="chevron-right" size={18} color={colors.icon + '60'} />
|
|
</Pressable>
|
|
))
|
|
}
|
|
</View>
|
|
|
|
</View>
|
|
</ScrollView>
|
|
|
|
<DrawerBottom animation="slide" isVisible={isModal} setVisible={setModal} title={chooseUser.name}>
|
|
<View style={Styles.rowItemsCenter}>
|
|
<MenuItemRow
|
|
icon={<MaterialCommunityIcons name="account-eye" color={colors.text} size={25} />}
|
|
title="Lihat Profil"
|
|
onPress={() => {
|
|
setModal(false)
|
|
router.push(`/member/${chooseUser.idUser}`)
|
|
}}
|
|
/>
|
|
{canManage && (
|
|
<MenuItemRow
|
|
icon={<MaterialCommunityIcons name="account-remove" color={colors.text} size={25} />}
|
|
title="Keluarkan"
|
|
onPress={() => {
|
|
setModal(false)
|
|
setTimeout(() => setShowDeleteModal(true), 600)
|
|
}}
|
|
/>
|
|
)}
|
|
</View>
|
|
</DrawerBottom>
|
|
|
|
<ModalConfirmation
|
|
visible={showDeleteModal}
|
|
title="Konfirmasi"
|
|
message="Apakah anda yakin ingin mengeluarkan anggota?"
|
|
onConfirm={() => { setShowDeleteModal(false); handleDeleteUser() }}
|
|
onCancel={() => setShowDeleteModal(false)}
|
|
confirmText="Hapus"
|
|
cancelText="Batal"
|
|
/>
|
|
</SafeAreaView>
|
|
)
|
|
} |