upd: divisi

Deskripsi:
- load data divisi
- user role pada page list divisi
- detail divisi
- info divisi
- tambah anggota divisi
- hapus anggota divisi
- update status admin divisi

No Issues
This commit is contained in:
amel
2025-05-21 15:57:03 +08:00
parent 2db0b45964
commit 1f5e00e612
12 changed files with 536 additions and 148 deletions

View File

@@ -0,0 +1,163 @@
import ButtonBackHeader from "@/components/buttonBackHeader";
import ButtonSaveHeader from "@/components/buttonSaveHeader";
import ImageUser from "@/components/imageNew";
import ImageWithLabel from "@/components/imageWithLabel";
import InputSearch from "@/components/inputSearch";
import Styles from "@/constants/Styles";
import { apiAddMemberDivision, apiGetDivisionOneDetail, apiGetProjectOne, apiGetUser } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { AntDesign } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { Pressable, SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native";
type Props = {
idUser: string,
name: string,
img: string
}
export default function AddMemberDivision() {
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>()
const [dataOld, setDataOld] = useState<Props[]>([])
const [data, setData] = useState<Props[]>([])
const [idGroup, setIdGroup] = useState('')
const [selectMember, setSelectMember] = useState<any[]>([])
const [search, setSearch] = useState('')
async function handleLoad() {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiGetDivisionOneDetail({ user: hasil, id })
setDataOld(response.data.member)
setIdGroup(response.data.division.idGroup)
const responsemember = await apiGetUser({ user: hasil, active: "true", search: search, group: String(response.data.division.idGroup) })
setData(responsemember.data.filter((i: any) => i.idUserRole != 'supadmin'))
} catch (error) {
console.error(error)
}
}
async function handleLoadMember(search: string) {
const hasil = await decryptToken(String(token?.current))
const response = await apiGetUser({ user: hasil, active: "true", search: search, group: String(idGroup) })
setData(response.data.filter((i: any) => i.idUserRole != 'supadmin'))
}
useEffect(() => {
handleLoad()
}, []);
function handleSearch(search: string) {
setSearch(search)
handleLoadMember(search)
}
function onChoose(val: string, label: string, img?: string) {
if (selectMember.some((i: any) => i.idUser == val)) {
setSelectMember(selectMember.filter((i: any) => i.idUser != val))
} else {
setSelectMember([...selectMember, { idUser: val, name: label, img }])
}
}
async function handleAddMember() {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiAddMemberDivision({ id: id, data: { user: hasil, member: selectMember } })
if (response.success) {
ToastAndroid.show('Berhasil menambahkan anggota', ToastAndroid.SHORT)
router.replace(`/division/${id}/info`)
} else {
ToastAndroid.show(response.message, ToastAndroid.SHORT)
}
} catch (error) {
console.error(error)
ToastAndroid.show('Gagal menambahkan anggota', ToastAndroid.SHORT)
}
}
return (
<SafeAreaView>
<Stack.Screen
options={{
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
headerTitle: 'Tambah Anggota',
headerTitleAlign: 'center',
headerRight: () => (
<ButtonSaveHeader
category="update"
disable={selectMember.length > 0 ? false : true}
onPress={() => {
handleAddMember()
}}
/>
)
}}
/>
<View style={[Styles.p15]}>
<InputSearch onChange={(val) => handleSearch(val)} value={search} />
{
selectMember.length > 0
?
<View>
<ScrollView horizontal style={[Styles.mb10, Styles.pv10]}>
{
selectMember.map((item: any, index: any) => (
<ImageWithLabel
key={index}
label={item.name}
src={item.img}
onClick={() => onChoose(item.idUser, item.name, item.img)}
/>
))
}
</ScrollView>
</View>
:
<Text style={[Styles.textDefault, Styles.cGray, Styles.pv05, { textAlign: 'center' }]}>Tidak ada member yang dipilih</Text>
}
<ScrollView>
{
data.length > 0 ?
data.map((item: any, index: any) => {
const found = dataOld.some((i: any) => i.idUser == item.id)
return (
<Pressable
key={index}
style={[Styles.itemSelectModal]}
onPress={() => {
!found && onChoose(item.id, item.name, item.img)
}}
>
<View style={[Styles.rowItemsCenter]}>
<ImageUser src={`https://wibu-storage.wibudev.com/api/files/${item.img}`} border />
<View style={[Styles.ml10]}>
<Text style={[Styles.textDefault]} numberOfLines={1} ellipsizeMode="tail">{item.name}</Text>
{
found && <Text style={[Styles.textInformation, Styles.cGray]}>sudah menjadi anggota</Text>
}
</View>
</View>
{
selectMember.some((i: any) => i.idUser == item.id) && <AntDesign name="check" size={20} />
}
</Pressable>
)
}
)
:
<Text style={[Styles.textDefault, { textAlign: 'center' }]}>Tidak ada data</Text>
}
</ScrollView>
</View>
</SafeAreaView>
)
}

View File

@@ -6,17 +6,51 @@ import HeaderRightDivisionDetail from "@/components/division/headerDivisionDetai
import TaskDivisionDetail from "@/components/division/taskDivisionDetail"
import CaraouselHome from "@/components/home/carouselHome"
import Styles from "@/constants/Styles"
import { apiGetDivisionOneDetail } from "@/lib/api"
import { useAuthSession } from "@/providers/AuthProvider"
import { router, Stack, useLocalSearchParams } from "expo-router"
import { useEffect, useState } from "react"
import { SafeAreaView, ScrollView, View } from "react-native"
type Props = {
id: string,
idVillage: string,
idGroup: string,
name: string,
desc: string,
isActive: boolean,
}
export default function DetailDivisionFitur() {
const { id } = useLocalSearchParams()
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>()
const [data, setData] = useState<Props>()
const [loading, setLoading] = useState(true)
async function handleLoad() {
try {
setLoading(true)
const hasil = await decryptToken(String(token?.current))
const response = await apiGetDivisionOneDetail({ user: hasil, id })
setData(response.data.division)
} catch (error) {
console.error(error)
} finally {
setLoading(false)
}
}
useEffect(() => {
handleLoad()
}, [])
return (
<SafeAreaView>
<Stack.Screen
options={{
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
headerTitle: 'Judul Divisi',
headerTitle: loading ? 'Loading...' : data?.name,
headerTitleAlign: 'center',
headerRight: () => <HeaderRightDivisionDetail id={id} />,
}}

View File

@@ -3,31 +3,109 @@ import BorderBottomItem from "@/components/borderBottomItem"
import ButtonBackHeader from "@/components/buttonBackHeader"
import HeaderRightDivisionInfo from "@/components/division/headerDivisionInfo"
import DrawerBottom from "@/components/drawerBottom"
import ImageUser from "@/components/imageNew"
import { ColorsStatus } from "@/constants/ColorsStatus"
import Styles from "@/constants/Styles"
import { apiDeleteMemberDivision, apiGetDivisionOneDetail, apiUpdateStatusAdminDivision } from "@/lib/api"
import { useAuthSession } from "@/providers/AuthProvider"
import { Feather, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"
import { router, Stack, useLocalSearchParams } from "expo-router"
import { useState } from "react"
import { Image, Pressable, SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native"
import { useEffect, useState } from "react"
import { Pressable, SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native"
type PropsDetail = {
id: string,
idVillage: string,
idGroup: string,
name: string,
desc: string,
isActive: boolean,
}
type PropsMember = {
id: string,
isAdmin: boolean,
isLeader: boolean,
idUser: string,
name: string,
img: string
}
export default function InformationDivision() {
const { id } = useLocalSearchParams()
const { id } = useLocalSearchParams<{ id: string }>()
const [isModal, setModal] = useState(false)
const { token, decryptToken } = useAuthSession()
const [dataDetail, setDataDetail] = useState<PropsDetail>()
const [dataMember, setDataMember] = useState<PropsMember[]>([])
const [refresh, setRefresh] = useState(false)
const [dataMemberChoose, setDataMemberChoose] = useState({
id: '',
name: '',
isAdmin: false
})
function handleMemberOut() {
AlertKonfirmasi({
title: 'Konfirmasi',
desc: 'Apakah anda yakin ingin mengeluarkan anggota?',
onPress: () => {
ToastAndroid.show('Berhasil mengeluarkan anggota', ToastAndroid.SHORT)
setModal(false)
}
onPress: () => { memberOut() }
})
}
function handleMemberAdmin() {
ToastAndroid.show('Berhasil memberhentikan admin', ToastAndroid.SHORT)
setModal(false)
async function memberOut() {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiDeleteMemberDivision({ user: hasil, id: dataMemberChoose.id }, id)
if (response.success) {
setRefresh(!refresh)
ToastAndroid.show('Berhasil mengeluarkan anggota', ToastAndroid.SHORT)
} else {
ToastAndroid.show(response.message, ToastAndroid.SHORT)
}
} catch (error) {
console.error(error)
ToastAndroid.show('Terjadi kesalahan', ToastAndroid.SHORT)
} finally {
setModal(false)
}
}
async function handleMemberAdmin() {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiUpdateStatusAdminDivision({ user: hasil, id: dataMemberChoose.id, isAdmin: dataMemberChoose.isAdmin }, id)
if (response.success) {
setRefresh(!refresh)
ToastAndroid.show(dataMemberChoose.isAdmin ? 'Berhasil memberhentikan admin' : 'Berhasil menjadi admin', ToastAndroid.SHORT)
} else {
ToastAndroid.show(response.message, ToastAndroid.SHORT)
}
} catch (error) {
console.error(error)
ToastAndroid.show('Terjadi kesalahan', ToastAndroid.SHORT)
} finally {
setModal(false)
}
}
async function handleLoad() {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiGetDivisionOneDetail({ user: hasil, id })
setDataDetail(response.data.division)
setDataMember(response.data.member)
} catch (error) {
console.error(error)
}
}
useEffect(() => {
handleLoad()
}, [refresh])
function handleChooseMember(item: PropsMember) {
setDataMemberChoose(item)
setModal(true)
}
return (
@@ -45,13 +123,14 @@ export default function InformationDivision() {
<View style={[Styles.mb15]}>
<Text style={[Styles.textDefaultSemiBold, Styles.mb05]}>Deskripsi Divisi</Text>
<View style={[Styles.wrapPaper]}>
<Text>There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable.</Text>
<Text>{dataDetail?.desc}</Text>
</View>
</View>
<View style={[Styles.mb15]}>
<Text style={[Styles.textDefault, Styles.mv05]}>5 Anggota</Text>
<Text style={[Styles.textDefault, Styles.mv05]}>{dataMember.length} Anggota</Text>
<View style={[Styles.wrapPaper]}>
<BorderBottomItem
onPress={() => { router.push(`/division/${id}/add-member`) }}
borderType="none"
icon={
<View style={[Styles.iconContent, ColorsStatus.gray]}>
@@ -60,73 +139,29 @@ export default function InformationDivision() {
}
title="Tambah Anggota"
/>
<BorderBottomItem
borderType="bottom"
onPress={() => { setModal(true) }}
icon={
<Image
source={require("../../../../assets/images/user.jpeg")}
style={[Styles.userProfileSmall]}
/>
}
title="Amalia Dwi"
rightTopInfo="Admin"
/>
<BorderBottomItem
borderType="bottom"
onPress={() => { setModal(true) }}
icon={
<Image
source={require("../../../../assets/images/user.jpeg")}
style={[Styles.userProfileSmall]}
/>
}
title="Amalia Dwi"
rightTopInfo="Admin"
/>
<BorderBottomItem
borderType="bottom"
onPress={() => { setModal(true) }}
icon={
<Image
source={require("../../../../assets/images/user.jpeg")}
style={[Styles.userProfileSmall]}
/>
}
title="Amalia Dwi"
rightTopInfo="Anggota"
/>
<BorderBottomItem
borderType="bottom"
onPress={() => { setModal(true) }}
icon={
<Image
source={require("../../../../assets/images/user.jpeg")}
style={[Styles.userProfileSmall]}
/>
}
title="Amalia Dwi"
rightTopInfo="Anggota"
/>
<BorderBottomItem
borderType="bottom"
onPress={() => { setModal(true) }}
icon={
<Image
source={require("../../../../assets/images/user.jpeg")}
style={[Styles.userProfileSmall]}
/>
}
title="Amalia Dwi"
rightTopInfo="Anggota"
/>
{
dataMember.map((item, index) => {
return (
<BorderBottomItem
width={55}
key={index}
borderType="bottom"
onPress={() => { handleChooseMember(item) }}
icon={
<ImageUser src={`https://wibu-storage.wibudev.com/api/files/${item.img}`} size="sm" />
}
title={item.name}
rightTopInfo={item.isAdmin ? "Admin" : "Anggota"}
/>
)
})
}
</View>
</View>
</View>
</ScrollView>
<DrawerBottom animation="slide" isVisible={isModal} setVisible={setModal} title="Amalia">
<DrawerBottom animation="slide" isVisible={isModal} setVisible={setModal} title={dataMemberChoose.name}>
<View>
<Pressable style={[Styles.wrapItemBorderBottom]} onPress={() => { handleMemberAdmin() }}>
<View style={[Styles.rowItemsCenter]}>
@@ -135,7 +170,7 @@ export default function InformationDivision() {
</View>
<View style={[Styles.rowSpaceBetween, { width: '88%' }]}>
<View style={[Styles.ml10]}>
<Text style={[Styles.textDefault]}>Memberhentikan sebagai admin</Text>
<Text style={[Styles.textDefault]}>{dataMemberChoose.isAdmin ? 'Memberhentikan sebagai admin' : 'Jadikan admin'}</Text>
</View>
</View>
</View>

View File

@@ -26,8 +26,8 @@ export default function BorderBottomItem({ title, subtitle, icon, desc, onPress,
<Pressable style={[borderType == 'bottom' ? Styles.wrapItemBorderBottom : borderType == 'all' ? Styles.wrapItemBorderAll : Styles.wrapItemBorderNone, bgColor && bgColor == 'white' && ColorsStatus.white]} onPress={onPress}>
<View style={[Styles.rowItemsCenter]}>
{icon}
<View style={[Styles.rowSpaceBetween, width ? { width: lebar } : { width: '88%' }]}>
<View style={[Styles.ml10]}>
<View style={[Styles.rowSpaceBetween, width ? { width: lebar } : { width: '88%' },]}>
<View style={[Styles.ml10, width ? { width: lebar } : { width: '88%' }]}>
<Text style={[titleWeight == 'normal' ? Styles.textDefault : Styles.textDefaultSemiBold]} numberOfLines={1} ellipsizeMode='tail'>{title}</Text>
{
subtitle &&

View File

@@ -13,7 +13,7 @@ export default function DiscussionItem({ title, user, date }: Props) {
<View style={[Styles.wrapItemDiscussion]}>
<View style={[Styles.rowItemsCenter, Styles.mb10]}>
<Ionicons name="chatbox-ellipses-outline" size={22} color="black" style={Styles.mr10} />
<Text style={{ fontWeight: 'bold' }}>{title}</Text>
<Text style={{ fontWeight: 'bold' }} numberOfLines={1} ellipsizeMode="tail">{title}</Text>
</View>
<View style={Styles.rowSpaceBetween}>
<View style={Styles.rowItemsCenter}>

View File

@@ -1,15 +1,49 @@
import Styles from "@/constants/Styles";
import { apiGetDivisionOneFeature } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { Text, View } from "react-native";
import DiscussionItem from "../discussionItem";
type Props = {
id: string
title: string
desc: string
user: string
date: string
}
export default function DiscussionDivisionDetail() {
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>()
const [data, setData] = useState<Props[]>([])
async function handleLoad() {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiGetDivisionOneFeature({ user: hasil, id, cat: 'new-discussion' })
setData(response.data)
} catch (error) {
console.error(error)
}
}
useEffect(() => {
handleLoad()
}, [])
return (
<View style={[Styles.mb15]}>
<Text style={[Styles.textDefaultSemiBold, Styles.mv10]}>Diskusi</Text>
<View style={[Styles.wrapPaper]}>
<DiscussionItem title="Bagaimana cara mengatasi banjir?" user="Amalia" date="13 Februari 2025" />
<DiscussionItem title="Bagaimana cara mengatasi banjir?" user="Amalia" date="13 Februari 2025" />
<DiscussionItem title="Bagaimana cara mengatasi banjir?" user="Amalia" date="13 Februari 2025" />
{
data.length > 0 ?
data.map((item, index) => (
<DiscussionItem key={index} title={item.desc} user={item.user} date={item.date} />
))
:
<Text style={[Styles.textDefault, Styles.cGray, { textAlign: 'center' }]}>Tidak ada diskusi</Text>
}
</View>
</View>
)

View File

@@ -1,49 +1,80 @@
import Styles from "@/constants/Styles";
import { Feather } from "@expo/vector-icons";
import React from "react";
import React, { useEffect, useState } from "react";
import { Dimensions, Text, View } from "react-native";
import Carousel, { ICarouselInstance } from "react-native-reanimated-carousel";
import { useAuthSession } from "@/providers/AuthProvider";
import { useLocalSearchParams } from "expo-router";
import { apiGetDivisionOneFeature } from "@/lib/api";
type Props = {
id: string
name: string
extension: string
path: string
share: boolean
}
export default function FileDivisionDetail() {
const data = [...new Array(6).keys()];
const ref = React.useRef<ICarouselInstance>(null);
const width = Dimensions.get("window").width;
const [data, setData] = useState<Props[]>([])
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>()
async function handleLoad() {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiGetDivisionOneFeature({ user: hasil, id, cat: 'new-file' })
setData(response.data)
} catch (error) {
console.error(error)
}
}
useEffect(() => {
handleLoad()
}, [])
return (
<View style={[Styles.mb15]}>
<Text style={[Styles.textDefaultSemiBold, Styles.mv10]}>Dokumen Terkini</Text>
<Carousel
ref={ref}
width={width}
height={115}
data={data}
loop={true}
autoPlay={false}
autoPlayReverse={false}
pagingEnabled={true}
snapEnabled={true}
vertical={false}
style={{
width: width,
}}
mode="parallax"
modeConfig={{
parallaxScrollingScale: 1,
parallaxScrollingOffset: 280,
}}
renderItem={({ index }) => (
<View style={{ margin: 'auto', width:'28%' }}>
<View style={{alignItems:'center'}}>
<View style={[Styles.wrapPaper, { alignItems: 'center' }]}>
<Feather name="file-text" size={50} color="black" style={Styles.mr05} />
{
data.length > 0 ?
<Carousel
ref={ref}
width={width}
height={115}
data={data}
loop={true}
autoPlay={false}
autoPlayReverse={false}
pagingEnabled={true}
snapEnabled={true}
vertical={false}
style={{
width: width,
}}
mode="parallax"
modeConfig={{
parallaxScrollingScale: 1,
parallaxScrollingOffset: 280,
}}
renderItem={({ index }) => (
<View style={{ margin: 'auto', width: '28%' }}>
<View style={{ alignItems: 'center' }}>
<View style={[Styles.wrapPaper, { alignItems: 'center' }]}>
<Feather name="file-text" size={50} color="black" style={Styles.mr05} />
</View>
</View>
<Text style={[Styles.textMediumNormal, { textAlign: 'center' }]} numberOfLines={1}>{data[index].name}.{data[index].extension}</Text>
</View>
</View>
<Text style={[Styles.textMediumNormal, { textAlign: 'center' }]} numberOfLines={1}>File_Pertama.png Amalia Dwi</Text>
</View>
)}
/>
)}
/>
:
<Text style={[Styles.textDefault, Styles.cGray, { textAlign: 'center' }]}>Tidak ada file</Text>
}
</View>
)
}

View File

@@ -1,12 +1,45 @@
import { ColorsStatus } from "@/constants/ColorsStatus"
import Styles from "@/constants/Styles"
import { apiGetDivisionOneFeature } from "@/lib/api"
import { useAuthSession } from "@/providers/AuthProvider"
import { AntDesign, MaterialIcons, SimpleLineIcons } from "@expo/vector-icons"
import { router, useLocalSearchParams } from "expo-router"
import { useEffect, useState } from "react"
import { Text, View } from "react-native"
import BorderBottomItem from "../borderBottomItem"
import { router, useLocalSearchParams } from "expo-router"
type Props = {
tugas: number
dokumen: number
diskusi: number
kalender: number
}
export default function FiturDivisionDetail() {
const { id } = useLocalSearchParams()
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>()
const [data, setData] = useState<Props>({
tugas: 0,
dokumen: 0,
diskusi: 0,
kalender: 0,
})
async function handleLoad() {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiGetDivisionOneFeature({ user: hasil, id, cat: 'jumlah' })
setData(response.data)
} catch (error) {
console.error(error)
}
}
useEffect(() => {
handleLoad()
}, [])
return (
<View style={[Styles.mb15]}>
@@ -22,7 +55,7 @@ export default function FiturDivisionDetail() {
</View>
}
title="Tugas"
subtitle='15 Tugas'
subtitle={`${data.tugas} Tugas`}
width={28}
onPress={() => { router.push(`/division/${id}/task?status=0`) }}
/>
@@ -36,7 +69,7 @@ export default function FiturDivisionDetail() {
</View>
}
title="Dokumen"
subtitle='20 File'
subtitle={`${data.dokumen} File`}
width={28}
onPress={() => { router.push(`/division/${id}/document`) }}
/>
@@ -52,7 +85,7 @@ export default function FiturDivisionDetail() {
</View>
}
title="Diskusi"
subtitle='5 Diskusi'
subtitle={`${data.diskusi} Diskusi`}
width={28}
onPress={() => { router.push(`/division/${id}/discussion?active=true`) }}
/>
@@ -66,7 +99,7 @@ export default function FiturDivisionDetail() {
</View>
}
title="Kalender"
subtitle='23 Acara'
subtitle={`${data.kalender} Acara`}
width={28}
onPress={() => { router.push(`/division/${id}/calendar`) }}
/>

View File

@@ -24,7 +24,7 @@ export default function HeaderRightDivisionDetail({ id }: Props) {
title="Informasi Divisi"
onPress={() => {
setVisible(false)
router.push('/division/123/info')
router.push(`/division/${id}/info`)
}}
/>
<MenuItemRow
@@ -32,7 +32,7 @@ export default function HeaderRightDivisionDetail({ id }: Props) {
title="Laporan Divisi"
onPress={() => {
setVisible(false)
router.push('/division/123/report')
router.push(`/division/${id}/report`)
}}
/>
</View>

View File

@@ -1,39 +1,72 @@
import Styles from "@/constants/Styles";
import { apiGetDivisionOneFeature } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { Feather } from "@expo/vector-icons";
import React from "react";
import { useLocalSearchParams } from "expo-router";
import React, { useEffect, useState } from "react";
import { Dimensions, Text, View } from "react-native";
import Carousel, { ICarouselInstance } from "react-native-reanimated-carousel";
type Props = {
id: string
idProject: string
title: string
dateStart: string
dateEnd: string
projectTitle: string
}
export default function TaskDivisionDetail() {
const data = [...new Array(6).keys()];
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>()
const [data, setData] = useState<Props[]>([])
const ref = React.useRef<ICarouselInstance>(null);
const width = Dimensions.get("window").width;
async function handleLoad() {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiGetDivisionOneFeature({ user: hasil, id, cat: 'today-task' })
setData(response.data)
} catch (error) {
console.error(error)
}
}
useEffect(() => {
handleLoad()
}, [])
return (
<View>
<Text style={[Styles.textDefaultSemiBold, Styles.mb05]}>Tugas Hari Ini</Text>
<Carousel
ref={ref}
style={{ width: "100%" }}
width={width * 0.8}
height={100}
data={data}
loop={true}
autoPlay={false}
autoPlayReverse={false}
pagingEnabled={true}
snapEnabled={true}
vertical={false}
renderItem={({ index }) => (
<View style={[Styles.wrapPaper, { width: '95%'}]}>
<Text style={[Styles.textDefaultSemiBold]}>Rancangan Laporan - Laporan 1</Text>
<View style={[Styles.rowItemsCenter, Styles.mt10]}>
<Feather name="clock" size={18} color="grey" style={Styles.mr05} />
<Text style={[Styles.textInformation]}>5 Mar 2025 - 12 Mar 2025</Text>
</View>
</View>
)}
/>
{
data.length > 0 ?
<Carousel
ref={ref}
style={{ width: "100%" }}
width={width * 0.8}
height={100}
data={data}
loop={true}
autoPlay={false}
autoPlayReverse={false}
pagingEnabled={true}
snapEnabled={true}
vertical={false}
renderItem={({ index }) => (
<View style={[Styles.wrapPaper, { width: '95%' }]}>
<Text style={[Styles.textDefaultSemiBold]} numberOfLines={1} ellipsizeMode="tail">{data[index].title} - {data[index].projectTitle}</Text>
<View style={[Styles.rowItemsCenter, Styles.mt10]}>
<Feather name="clock" size={18} color="grey" style={Styles.mr05} />
<Text style={[Styles.textInformation]} numberOfLines={1} ellipsizeMode="tail">{data[index].dateStart} - {data[index].dateEnd}</Text>
</View>
</View>
)}
/>
:
<Text style={[Styles.textDefault, Styles.cGray, { textAlign: 'center' }]}>Tidak ada tugas</Text>
}
</View>
)
}

View File

@@ -12,7 +12,7 @@ export default function ImageWithLabel({ src, label, onClick }: Props) {
return (
<TouchableOpacity style={[Styles.contentItemCenter, Styles.mh05]} onPress={onClick}>
<ImageUser src={src} border />
<Text>{label}</Text>
<Text numberOfLines={1} ellipsizeMode="tail">{label}</Text>
</TouchableOpacity>
)
}

View File

@@ -357,4 +357,29 @@ export const apiGetDivision = async ({ user, search, group, kategori, active }:
export const apiGetDivisionReport = async ({ user, cat, date, dateEnd, division, group }: { user: string, cat: string, date: string, dateEnd: string, division: string, group?: string }) => {
const response = await api.get(`mobile/division/report?user=${user}&cat=${cat}&date=${date}&date-end=${dateEnd}&division=${division}&group=${group}`);
return response.data;
};
};
export const apiGetDivisionOneFeature = async ({ user, cat, id }: { user: string, cat: 'jumlah' | 'today-task' | 'new-file' | 'new-discussion', id: string }) => {
const response = await api.get(`mobile/division/${id}/detail?user=${user}&cat=${cat}`);
return response.data;
};
export const apiGetDivisionOneDetail = async ({ user, id }: { user: string, id: string }) => {
const response = await api.get(`mobile/division/${id}?user=${user}`);
return response.data;
};
export const apiUpdateStatusAdminDivision = async (data: { user: string, id: string, isAdmin: boolean }, id: string) => {
const response = await api.put(`mobile/division/${id}/detail`, data)
return response.data
};
export const apiDeleteMemberDivision = async (data: { user: string, id: string }, id: string) => {
const response = await api.delete(`/mobile/division/${id}/detail`, { data })
return response.data;
};
export const apiAddMemberDivision = async ({ data, id }: { data: { user: string, member: any[] }, id: string }) => {
const response = await api.post(`/mobile/division/${id}/detail`, data)
return response.data;
};