From 97726609e13ace824db352ebf0425f965006d1ba Mon Sep 17 00:00:00 2001 From: amaliadwiy Date: Wed, 6 May 2026 16:23:35 +0800 Subject: [PATCH] feat: redesign section member dan fix warna dimmed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SectionMember & SectionMemberTask: ganti BorderBottomItem dengan card item custom (avatar + nama + badge jabatan), skeleton baru, label jumlah anggota - Colors.ts: hapus suffix alpha '#707887ff' → '#707887' pada warna dimmed Co-Authored-By: Claude Sonnet 4.6 --- components/project/sectionMember.tsx | 179 +++++++++++--------------- components/task/sectionMemberTask.tsx | 73 ++++++++--- constants/Colors.ts | 2 +- 3 files changed, 135 insertions(+), 119 deletions(-) diff --git a/components/project/sectionMember.tsx b/components/project/sectionMember.tsx index 9999ec5..5a4dd99 100644 --- a/components/project/sectionMember.tsx +++ b/components/project/sectionMember.tsx @@ -7,15 +7,14 @@ import { useTheme } from "@/providers/ThemeProvider"; import { MaterialCommunityIcons } from "@expo/vector-icons"; import { router, useLocalSearchParams } from "expo-router"; import { useEffect, useState } from "react"; -import { View } from "react-native"; +import { Pressable, View } from "react-native"; import Toast from "react-native-toast-message"; import { useDispatch, useSelector } from "react-redux"; -import ModalConfirmation from "../ModalConfirmation"; -import BorderBottomItem from "../borderBottomItem"; import DrawerBottom from "../drawerBottom"; import ImageUser from "../imageNew"; import MenuItemRow from "../menuItemRow"; -import SkeletonTwoItem from "../skeletonTwoItem"; +import ModalConfirmation from "../ModalConfirmation"; +import Skeleton from "../skeleton"; import Text from "../Text"; type Props = { @@ -35,26 +34,17 @@ export default function SectionMember({ status, refreshing }: { status: number | const [isModal, setModal] = useState(false); const { token, decryptToken } = useAuthSession(); const { id } = useLocalSearchParams<{ id: string }>(); - const [selectLink, setSelectLink] = useState(null); const [showDeleteModal, setShowDeleteModal] = useState(false); const [data, setData] = useState([]); const [loading, setLoading] = useState(true) - const arrSkeleton = Array.from({ length: 3 }) - const [memberChoose, setMemberChoose] = useState({ - id: '', - name: '', - }) - + const arrSkeleton = Array.from({ length: 4 }) + const [memberChoose, setMemberChoose] = useState({ id: '', name: '' }) async function handleLoad(loading: boolean) { try { setLoading(loading) const hasil = await decryptToken(String(token?.current)); - const response = await apiGetProjectOne({ - user: hasil, - cat: "member", - id: id, - }); + const response = await apiGetProjectOne({ user: hasil, cat: "member", id }); setData(response.data); } catch (error) { console.error(error); @@ -63,36 +53,21 @@ export default function SectionMember({ status, refreshing }: { status: number | } } - useEffect(() => { - handleLoad(false); - }, [update.member]); - - useEffect(() => { - if (refreshing) - handleLoad(false); - }, [refreshing]); - - useEffect(() => { - handleLoad(true); - }, []); + useEffect(() => { handleLoad(false) }, [update.member]); + useEffect(() => { if (refreshing) handleLoad(false) }, [refreshing]); + useEffect(() => { handleLoad(true) }, []); async function handleDeleteMember() { try { const hasil = await decryptToken(String(token?.current)); - const response = await apiDeleteProjectMember({ - user: hasil, - idUser: memberChoose.id, - }, id) + const response = await apiDeleteProjectMember({ user: hasil, idUser: memberChoose.id }, id) if (response.success) { - Toast.show({ type: 'small', text1: 'Berhasil menghapus anggota', }) + Toast.show({ type: 'small', text1: 'Berhasil menghapus anggota' }) dispatch(setUpdateProject({ ...update, member: !update.member })) setModal(false); } - } catch (error : any ) { - console.error(error); - const message = error?.response?.data?.message || "Gagal menghapus anggota" - - Toast.show({ type: 'small', text1: message }) + } catch (error: any) { + Toast.show({ type: 'small', text1: error?.response?.data?.message || "Gagal menghapus anggota" }) } } @@ -101,84 +76,85 @@ export default function SectionMember({ status, refreshing }: { status: number | Anggota - Total {data.length} Anggota + {!loading && data.length > 0 && ( + {data.length} orang + )} - - { - loading ? - arrSkeleton.map((item, index) => { - return ( - - ) - }) - : - data.length > 0 - ? - data.map((item, index) => { - return ( - } - title={item.name} - onPress={() => { - if (status == 3) return - setMemberChoose({ - id: item.idUser, - name: item.name, - }) - setModal(true); - }} - /> - ); - }) - : - Tidak ada anggota - } + + {loading ? ( + arrSkeleton.map((_, index) => ( + + + + + + + + )) + ) : data.length > 0 ? ( + data.map((item, index) => ( + { + if (status === 3) return + setMemberChoose({ id: item.idUser, name: item.name }) + setModal(true) + }} + style={{ + flexDirection: 'row', + alignItems: 'center', + backgroundColor: colors.card, + borderRadius: 10, + borderWidth: 1, + borderColor: colors.icon + '18', + paddingHorizontal: 12, + paddingVertical: 10, + gap: 12, + }} + > + + + {item.name} + + + + {item.position} + + + + )) + ) : ( + Tidak ada anggota + )} - + - } + icon={} title="Lihat Profil" onPress={() => { - setModal(false); - router.push(`/member/${memberChoose.id}`); + setModal(false) + router.push(`/member/${memberChoose.id}`) }} /> - { - entityUser.role != "user" && entityUser.role != "coadmin" && + {entityUser.role !== "user" && entityUser.role !== "coadmin" && ( - } + icon={} title="Keluarkan" onPress={() => { setModal(false) - setTimeout(() => { - setShowDeleteModal(true) - }, 600) + setTimeout(() => setShowDeleteModal(true), 600) }} /> - } + )} @@ -186,10 +162,7 @@ export default function SectionMember({ status, refreshing }: { status: number | visible={showDeleteModal} title="Konfirmasi" message="Apakah Anda yakin ingin mengeluarkan anggota?" - onConfirm={() => { - setShowDeleteModal(false) - handleDeleteMember() - }} + onConfirm={() => { setShowDeleteModal(false); handleDeleteMember() }} onCancel={() => setShowDeleteModal(false)} confirmText="Keluarkan" cancelText="Batal" diff --git a/components/task/sectionMemberTask.tsx b/components/task/sectionMemberTask.tsx index 61f3f0d..54209b7 100644 --- a/components/task/sectionMemberTask.tsx +++ b/components/task/sectionMemberTask.tsx @@ -7,15 +7,14 @@ import { useTheme } from "@/providers/ThemeProvider"; import { MaterialCommunityIcons } from "@expo/vector-icons"; import { router, useLocalSearchParams } from "expo-router"; import { useEffect, useState } from "react"; -import { View } from "react-native"; +import { Pressable, View } from "react-native"; import Toast from "react-native-toast-message"; import { useDispatch, useSelector } from "react-redux"; -import ModalConfirmation from "../ModalConfirmation"; -import BorderBottomItem from "../borderBottomItem"; import DrawerBottom from "../drawerBottom"; import ImageUser from "../imageNew"; import MenuItemRow from "../menuItemRow"; -import SkeletonTwoItem from "../skeletonTwoItem"; +import ModalConfirmation from "../ModalConfirmation"; +import Skeleton from "../skeleton"; import Text from "../Text"; type Props = { @@ -88,7 +87,7 @@ export default function SectionMemberTask({ refreshing, isAdminDivision }: { ref } else { Toast.show({ type: 'small', text1: response.message, }) } - } catch (error : any ) { + } catch (error: any) { console.error(error); const message = error?.response?.data?.message || "Gagal menghapus anggota" @@ -103,28 +102,46 @@ export default function SectionMemberTask({ refreshing, isAdminDivision }: { ref Anggota - Total {data.length} Anggota + {!loading && data.length > 0 && ( + {data.length} orang + )} - + { loading ? arrSkeleton.map((item, index) => { return ( - + + + + + + + ) }) : data.length > 0 ? ( data.map((item, index) => { return ( - + // } + // title={item.name} + // onPress={() => { + // setMemberChoose({ + // id: item.idUser, + // name: item.name, + // }); + // setModal(true); + // }} + // /> + - } - title={item.name} onPress={() => { setMemberChoose({ id: item.idUser, @@ -132,7 +149,33 @@ export default function SectionMemberTask({ refreshing, isAdminDivision }: { ref }); setModal(true); }} - /> + style={{ + flexDirection: 'row', + alignItems: 'center', + backgroundColor: colors.card, + borderRadius: 10, + borderWidth: 1, + borderColor: colors.icon + '18', + paddingHorizontal: 12, + paddingVertical: 10, + gap: 12, + }} + > + + + {item.name} + + + + {item.position} + + + ); }) ) : ( diff --git a/constants/Colors.ts b/constants/Colors.ts index 22215ae..99ed48a 100644 --- a/constants/Colors.ts +++ b/constants/Colors.ts @@ -13,7 +13,7 @@ export const Colors = { tabActive: '#2563EB', header: '#234881', homeGradient: '#346CC4', - dimmed: '#707887ff', + dimmed: '#707887', success: '#40C057', warning: '#FBBF24', error: '#F87171',