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

@@ -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>
)
}